Recently, I noticed odd traffic targeting my Ubuntu server. Connection attempts were coming in from unfamiliar IPs on high-numbered ports. At first glance, it looked like low-level noise. But patterns started to emerge that suggested automated scans or probing attempts, likely by bots.
If you’re running a public-facing server and haven’t taken the time to secure it beyond default installs, you’re leaving the door open. Here’s what I did, what I found, and what I recommend every new admin check immediately, along with additional essential hardening steps.
Step 1: Investigate Unexpected Network Activity
Start with your logs. I reviewed mine using sudo tail -f /var/log/kern.log
. Repeated UFW BLOCK entries flagged traffic from dozens of IP addresses. Most of them were hitting unusual high ports using TCP SYNs. This is typical of port scanning behavior, often probing for exposed services with known vulnerabilities.
To dig deeper, I ran sudo lsof -i -P -n | grep LISTEN
and sudo nmap your.public.ip
. This initial sweep helps identify what’s actively listening on your server and what’s visible from the outside.
Step 2: Harden the Server (Initial Steps)
Now that I had a clearer picture of the incoming traffic, I took time to harden the rest of the system. This is what I recommend every admin check immediately after spinning up an Ubuntu server:
Firewall
The Uncomplicated Firewall (UFW) is your first line of defense. Set up strong defaults:
Bash
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow ssh # Allows SSH access (port 22 by default) sudo ufw allow http # Allows web traffic (port 80) sudo ufw allow https # Allows secure web traffic (port 443) sudo ufw enable
SSH Configuration
Secure your SSH access. This is one of the most targeted services on any public-facing server. Edit /etc/ssh/sshd_config
:
PermitRootLogin no PasswordAuthentication no AllowUsers yourusername # Replace 'yourusername' with your actual username
After making these changes, reload the SSH daemon: sudo systemctl reload sshd
.
Disable Unused Services
Ubuntu comes with many services enabled by default that you might not need. Every active service is a potential attack vector. Disable anything you don’t use:
Bash
sudo systemctl disable --now avahi-daemon sudo systemctl disable --now cups sudo systemctl disable --now bluetooth # Disable anything else you know you are not using, e.g., print services, unnecessary network daemons.
Install Fail2Ban
One of the most immediate security upgrades you can make on a public-facing Linux server is to install and properly configure Fail2Ban. This tool actively scans authentication logs and bans IPs that show signs of brute-force attempts, unauthorized access, or malicious behavior.
On Ubuntu or Debian-based systems, installation is straightforward:
sudo apt update
sudo apt install fail2ban -y
The service will start automatically. You can confirm it’s running with:
sudo systemctl status fail2ban
Fail2Ban ships with default settings and jails, but for true protection you’ll want to harden those defaults.
Step 2: Best Practices Secure Configuration
Instead of editing the main config, create a safe override file:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Then edit the override file:
sudo nano /etc/fail2ban/jail.local
Use the following secure configuration block to lock down SSH access:
[DEFAULT]
# Ban duration - 24 hours for any offender
bantime = 24h
# Detection window - 3 failed attempts within 1 hour triggers a ban
findtime = 1h
maxretry = 3
# Log backend - Use journal for modern systems
backend = systemd
# Use UFW for banning IPs
banaction = ufw
banaction_allports = ufw
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
Why these settings matter:
bantime = 24h
: Keeps attackers out for a full day, slowing down their ability to retry.findtime = 1h
+maxretry = 3
: Very strict. Only 3 login failures are allowed per hour.banaction = ufw
: Directly integrates Fail2Ban with your firewall to enforce bans at the network level.backend = systemd
: Necessary for accurate log tracking on journal-based systems.enabled = true
: Activates the SSH protection jail.
Optional: Use
bantime = -1
for a permanent ban. This is effective for persistent abuse from a small range of IPs.
Once your configuration is saved, restart Fail2Ban to apply:
sudo systemctl restart fail2ban
Or reload without restarting:
sudo fail2ban-client reload
Monitoring Fail2Ban in Real-Time
To see which jails are active:
sudo fail2ban-client status
To inspect the SSH jail specifically:
sudo fail2ban-client status sshd
You’ll see output like:
Status for the jail: sshd
|- Filter
| |- Currently failed: 2
| |- Total failed: 45
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 10
|- Total banned: 20
`- Banned IP list: 103.187.146.152 185.93.89.52 ...
Step 3: Deep Dive into Unexpected Open Ports
Even after initial hardening, I kept monitoring. It wasn’t until later, after addressing the initial “noise,” that follow-up scans revealed an unexpected open port, one that had no legitimate business being accessible externally.
Understand the Risk
This particular open port was associated with a service used to map RPC services like NFS. If you’re not actively using NFS or similar RPC-based systems, having this port exposed is unnecessary and potentially dangerous. Worse, the service was active by default. No related mounts were configured, and no server was running, but the socket was still open and listening.
Shut Down the Unused Service
To disable this service properly (as an example, for rpcbind
on port 111):
Bash
sudo systemctl stop rpcbind sudo systemctl stop rpcbind.socket sudo systemctl disable rpcbind sudo systemctl disable rpcbind.socket
Then, explicitly deny it in your firewall and reload:
Bash
sudo ufw deny 111 sudo ufw reload
Re-running the Nmap scan confirmed that the port was no longer open. This highlighted the importance of persistence in security audits.
Step 4: Verify Exposure
Make verifying your server’s exposure a regular part of your routine. Periodically run:
Bash
sudo lsof -i -P -n | grep LISTEN sudo nmap your.public.ip
Know what is listening, and what is exposed. Never assume a port is closed because you didn’t open it.
Step 5: Essential Ongoing Hardening for All Ubuntu Servers
To truly harden your server, consider these additional crucial steps:
Keep System Up-to-Date (Automated Updates)
This is paramount. Most compromises exploit known vulnerabilities for which patches already exist.
Bash
sudo apt update && sudo apt upgrade sudo apt autoremove
For automated security updates, configure unattended-upgrades
: sudo dpkg-reconfigure --priority=low unattended-upgrades
. Ensure it’s enabled and regularly applying security patches.
Strong Passwords and Password Policies
Enforce robust password policies. This involves setting minimum length, complexity requirements, and password history using PAM (Pluggable Authentication Modules). Ensure no user can log in with an empty password.
User Management & Principle of Least Privilege
Always create a separate, non-root user for daily administrative tasks and use sudo
for elevated privileges. Configure /etc/sudoers
(using sudo visudo
) to limit which commands specific users or groups can run with sudo
. Regularly review and remove old or unused user accounts. Ensure only the root
account has a User ID (UID) of 0; check with awk -F: '($3=="0"){print}' /etc/passwd
.
Change Default SSH Port (Optional but Recommended)
While not a security silver bullet, moving SSH from port 22 can reduce the sheer volume of automated scanning attempts. Remember to update your UFW rules if you do this. Edit /etc/ssh/sshd_config
and change Port 22
to something else (e.g., Port 2222
). Reload the SSH daemon and update UFW.
Secure Shared Memory
By default, shared memory (/run/shm) can be mounted with read/write access, which can be exploited. Edit /etc/fstab and add/modify the line for /run/shm:
tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0
Reboot for changes to take effect.
File Integrity Monitoring (FIM)
Tools like AIDE (Advanced Intrusion Detection Environment) can detect unauthorized changes to critical system files.
Bash
sudo apt install aide aide-common sudo aideinit # Initialize the database sudo aide.wrapper --check # Run checks regularly via cron
Logging and Auditing
Consider forwarding your server logs to a centralized log management system so that logs cannot be tampered with or deleted by an attacker on the compromised server. The Linux Auditing System (auditd
) provides detailed logging of system calls and events, invaluable for forensic analysis. Make regular log review a habit, either manually or using tools like Logwatch.
AppArmor
AppArmor is Ubuntu’s default Mandatory Access Control system. Verify that it is active and that profiles are loaded:
sudo apparmor_status
If it is not active, then investigate why and enable it.
Regular Backups & Disaster Recovery
This is critical. No security measure is foolproof. Have a robust backup strategy (e.g., 3-2-1 rule: 3 copies, 2 different media, 1 offsite) and regularly test your restoration procedures.
Conclusion
Many default services on Ubuntu are enabled whether you use them or not. It’s your responsibility to turn off what you do not need. Every open port is a potential point of failure. Running a public-facing server without basic hardening is asking for trouble.
If you’re new to managing servers, make auditing your services and firewall configuration part of your normal routine. You may not be able to stop scanners from knocking, but you can ensure there’s nothing behind the door when they try.
If you’re unsure what a service does, look it up, or disable it and test. Start with fewer services and expand only as needed. Security starts with minimalism.
What tools, techniques, or habits have helped you keep your Linux servers secure?
Discover more from AJB Blog
Subscribe to get the latest posts sent to your email.