Securing an Ubuntu Server: A Practical Guide

Sept. 28, 2024 (updated) by @anthonynsimon

In this guide, I'll cover some common steps I've used to secure many Ubuntu servers over the years.

While this is not meant to be an exhaustive list, these are well-understood security measures to reduce the risk of unauthorized access, data breaches and loss of service.

1. Keep your system up-to-date

Regularly updating your system is one of the most important steps to keep your server secure. It ensures that you have the latest security patches and bug fixes.

apt update && apt upgrade -y

2. Set up a firewall

Ubuntu comes with a firewall called ufw. You can enable it and only allow the necessary ports. For example:

ufw allow ssh
ufw allow http
ufw allow https
ufw enable

3. Disable Password Authentication

Disable password authentication and use SSH keys instead. This will reduce the risk of brute-force attacks.

sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config
sed -i 's/#PermitEmptyPasswords no/PermitEmptyPasswords no/g' /etc/ssh/sshd_config
echo 'ChallengeResponseAuthentication no' >> /etc/ssh/sshd_config

You'll need to reload the SSH agent for these changes to take effect:

sudo systemctl reload ssh

4. Disable root login

Disable root login to prevent attackers from directly logging in as root. Instead, create a regular user with the necessary permissions and when needed, use sudo to run commands as root.

First, create a new user without a password (we only want to use SSH keys):

adduser --disabled-password  --gecos "" nonroot

Add the new user to the sudo group by appending this line to the /etc/sudoers file:

echo "nonroot ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

Next, allow the new user to log in via your SSH key:

AUTHORIZED_KEYS=$(cat ~/.ssh/authorized_keys)
sudo -H -u nonroot bash -c '
mkdir ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
'
sudo -H -u nonroot bash -c "echo '$AUTHORIZED_KEYS' >> ~/.ssh/authorized_keys"

If you're using Docker, you may also want to add the nonroot user to the docker group:

sudo usermod -aG docker nonroot

Exit the nonroot user shell to go back to the root user. Now, you can disable root login:

sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/g' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config

Restart the SSH service:

systemctl restart ssh

You can now log in as the nonroot user and use sudo to run commands as root.

5. Install Fail2ban

Fail2ban helps mitigate brute-force attacks by banning IPs after too many failed login attempts.

To install:

sudo apt install fail2ban

You can then configure Fail2ban by editing the /etc/fail2ban/jail.local file. For example:

cat <<EOF > /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 5
findtime = 600
bantime = 600
ignoreip = 127.0.0.1/8
logpath = /var/log/auth.log
EOF

After making changes, restart Fail2ban:

sudo systemctl restart fail2ban

You can then view SSH log in attempts with:

sudo tail -f /var/log/auth.log

6. Secure Shared Memory

Shared memory is a common attack vector. On one hand, it's an efficient way for processes to communicate, but it can also be exploited since multiple processes can access it and use it to escalate privileges or execute arbitrary code.

To secure shared memory, add the following line to /etc/fstab:

sudo echo "tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0" >> /etc/fstab

You'll need to reboot the server for this change to take effect.

sudo reboot

Command cheatsheet

Here are some useful commands to check the security of your Ubuntu server:

Ensure only root has UID 0

awk -F: '($3 == 0) {print}' /etc/passwd

List all users

cut -d: -f1 /etc/passwd

List users without password

awk -F: '($2 == "") {print}' /etc/shadow

Check disk usage in human-readable format

df -h

Only in current dir, order by size:

du -h -d 1 | sort -h

Check for listening ports

netstat -tuln
ss -tuln

Show active user sessions

w

Check banned IPs

zgrep 'Ban' /var/log/fail2ban.log*

Show Ubuntu version

lsb_release -a

Conclusion

These steps improve the security posture of an Ubuntu server. However, security is an ongoing process, and additional steps can further harden the system.

For example, you may also want to consider:

  • Scheduling automated backups
  • Checking your disks are encrypted
  • Setting up monitoring and alerting
  • Configuring your cloud provider's firewall or security groups
  • Use a private network to isolate your server from the public internet
  • Regularly scan for vulnerabilities and do system audits

I hope this guide is helpful to you. If you have any questions or suggestions, feel free to reach out to me on X/Twitter.