Guides/Secure Ubuntu 24.04

First Steps to Secure a New Ubuntu 24.04 VPS

10gpsvps ·

Line illustration of a terminal window with a padlock and a key, in front of a shield outline

Read this first

We have not run these commands on this product's image. They come from Ubuntu's documentation and packages, checked in November 2026. A mistake with SSH or a firewall can lock you out. Keep a second SSH session open the whole way through, check each step before you start the next one, and stop if a result is not what this guide says.

These are the first things to do on a new server running Ubuntu 24.04, which you can pick on any plan. You have full root access, so the server's security is yours to set up.

Replace username with the account name you want and your-server-ip with your server's address. The commands use sudo, which also works when you are logged in as root. The root password has been on your dashboard, so treat it as exposed until step 4 turns password login off.

1. Update the packages

sudo apt update
sudo apt upgrade

2. Create an admin user

sudo adduser username
sudo adduser username sudo

With one name, adduser creates a normal user and asks for a password. With two names, it adds an existing user to an existing group. Ubuntu's docs say the sudo group gives an account full root access through sudo. They also say the root account is disabled by default on Ubuntu installs, but a provider's image may differ, so do not assume it on yours.

3. Set up an SSH key

Run this on your own computer, not on the server:

ssh-keygen -t ed25519
ssh-copy-id username@your-server-ip

Ubuntu recommends ed25519. The alternative is RSA, with ssh-keygen -t rsa -b 4096.

Now log in with the key from a new terminal. Then confirm that only your user can write to the key file, and that sudo works:

ssh username@your-server-ip
chmod go-w .ssh/authorized_keys
sudo whoami

The login should use your key, not the account password, and the last command should print root. Do not go on until both are true, because the next step turns passwords off.

4. Turn off password login

Put the settings in a snippet of their own and leave the main file alone. The name 00-hardening.conf is our suggestion. What matters is that it sorts first.

sudo tee /etc/ssh/sshd_config.d/00-hardening.conf > /dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF

The 50-cloud-init.conf trap

Snippets in /etc/ssh/sshd_config.d/ are read at the start of sshd_config, in lexical order, and OpenSSH uses the first value it reads.

That matters because a file called 50-cloud-init.conf can set PasswordAuthentication yes. If it does, it silently beats a change in sshd_config itself and in any snippet that sorts after it. You turn passwords off, restart SSH, and they stay on. The fix a cloud-init maintainer gives is a file ordered before it, which is why ours starts with 00. We tested that order with OpenSSH 10.3 on a separate machine, not on Ubuntu 24.04: 00-hardening.conf won, and a change in the main file or in a file named 60- lost. See what your image has:

ls /etc/ssh/sshd_config.d/
sudo grep -r PasswordAuthentication /etc/ssh/sshd_config.d/

KbdInteractiveAuthentication is in the snippet because cloud-init's docs warn that PasswordAuthentication no may not be enough on images using PAM if that setting is yes. Ubuntu's package sets it to no by default, but do not assume it. Check the value in force, as shown next.

Test, apply, confirm

sudo sshd -t
sudo systemctl restart ssh.service
sudo sshd -T | grep -Ei \
  'passwordauthentication|kbdinteractiveauthentication|permitrootlogin'

sshd -t checks the configuration and prints nothing when it is fine. If it prints an error, fix that before you restart. sshd -T prints the values in force, and all three lines should end in no.

Keep this session open. From a second terminal, try all three of these:

ssh username@your-server-ip
ssh -o PubkeyAuthentication=no username@your-server-ip
ssh root@your-server-ip

The first should log you in. The other two should stop with Permission denied. If the first one fails, go back to the session you kept open and undo the change:

sudo rm /etc/ssh/sshd_config.d/00-hardening.conf
sudo systemctl restart ssh.service

5. Turn on the ufw firewall

ufw runs inside your server and you manage it yourself. It is not a feature of the plan. Ubuntu leaves it disabled at first. Upstream's default policy drops incoming connections once it is on, so allow SSH before you enable it.

sudo ufw allow 22
sudo ufw enable
sudo ufw status verbose

On enable, ufw warns that the command may disrupt existing ssh connections. Confirm only after the first command has added the rule. Then test a new login from your second terminal.

Open other ports the same way, for example for a web server:

sudo ufw allow 80

You can also rate-limit SSH. ufw limit denies an IP address that attempts 6 or more connections within 30 seconds. ufw stops at the first rule that matches, so the limit does nothing while the plain rule sits above it. Add the limit first, then remove the plain rule:

sudo ufw limit ssh/tcp
sudo ufw delete allow 22

6. Check automatic security updates

Ubuntu says unattended-upgrades is installed by default and applies security updates automatically, once a day. Check that this is true on your image:

cat /etc/apt/apt.conf.d/20auto-upgrades
sudo unattended-upgrade -v --dry-run

The file should contain these two lines:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

If the tool is missing, run sudo apt install unattended-upgrades. Its logs are in /var/log/unattended-upgrades, and its settings are in /etc/apt/apt.conf.d/50unattended-upgrades.

Automatic reboot is off by default, so a kernel update can sit waiting until you reboot the server yourself.

7. Add fail2ban

sudo apt update
sudo apt install fail2ban
sudo fail2ban-client status sshd

The package is in the universe repository. On 24.04 it ships with the SSH jail switched on, using nftables and the systemd journal, so the last command should show a jail called sshd.

If you read that fail2ban is broken on 24.04, that warning is out of date. The first build, 1.0.2-3, failed to start on Python 3.12 (bug 2055114). The fixed 1.0.2-3ubuntu0.1 reached noble-updates on 27 June 2024.

To change the limits, use /etc/fail2ban/jail.local and leave the .conf files as they are, as its manual advises. maxretry is the number of failures within findtime that bans an address, and bantime is how long the ban lasts. These values are only examples:

sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF'
[sshd]
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo systemctl restart fail2ban

fail2ban is an extra layer on top of your SSH key. Its README says it can reduce the rate of incorrect login attempts but "cannot eliminate the risk presented by weak authentication".

8. Optional: change the SSH port

A different port cuts the noise in your logs. It does not replace anything above.

Older guides are wrong on this point. Ubuntu's sshd is socket-activated, so if you change Port and restart ssh.service, nothing happens and it keeps listening on 22. An Ubuntu maintainer gives this sequence: put the port in a snippet, reload systemd, then restart the socket. Open the new port in ufw first. Port 2222 is only an example.

sudo ufw allow 2222
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/port.conf
sudo sshd -t
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
sudo ss -tlnp | grep -E ':(22|2222) '

The last command shows which ports are listening. Keep your session open and test from a second terminal:

ssh -p 2222 username@your-server-ip

If it fails, go back to the session you kept open and undo the change:

sudo rm /etc/ssh/sshd_config.d/port.conf
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket

When the new port works, remove your ufw rule for port 22. If you use fail2ban, add port = 2222 to the [sshd] section of jail.local and restart it, so that bans cover the new port.