A fresh Ubuntu server from any cloud provider comes up in a bad default state: you log in as root with a password, every port is answerable, and nothing updates itself. Bots start guessing SSH passwords against new servers within minutes of them getting a public IP. We watch it happen in the logs on every box we set up. This checklist is the first 30 minutes we spend on every new Ubuntu server, in order, with the actual commands. At the end you will have a server with key-only SSH on a locked-down firewall, automatic security patches, and brute-force protection.
Prerequisites
- A fresh Ubuntu 22.04 or 24.04 server and its root credentials (or a provider-created sudo user).
- A terminal on your own computer with an SSH client. macOS and Linux have one built in; Windows has it in PowerShell.
- About 30 minutes.
Step 1: Log in and update everything
First contact, then patch, because a fresh image is already weeks behind on updates:
ssh root@203.0.113.10
apt update && apt upgrade -y
If the upgrade pulls in a new kernel, reboot now (reboot) and log back in. Get it out of the way before you build on top.
Step 2: Create your own user with sudo
Day-to-day work should never happen as root. Create a normal user and put it in the sudo group:
adduser mason
usermod -aG sudo mason
adduser walks you through setting a password; the other fields can stay blank. Confirm the new account can actually elevate before you go further:
su - mason
sudo whoami # should print: root
exit
Do not skip that test. In a few steps we lock root out, and you want to be certain the new account works first.
Step 3: Set up SSH keys
Passwords can be guessed; keys realistically cannot. If you do not already have a key pair on your own computer, make one there (not on the server):
ssh-keygen -t ed25519
Accept the default location and set a passphrase. Then copy the public key to the new user on the server:
ssh-copy-id mason@203.0.113.10
Now confirm key login works in a new terminal window, while keeping your current session open as a safety line:
ssh mason@203.0.113.10
If it logs you in without asking for the account password (your key passphrase does not count), you are good.
Step 4: Turn off root login and password authentication
This is the step that ends the password-guessing game entirely. Edit the SSH daemon config:
sudo nano /etc/ssh/sshd_config
Find these lines, uncomment them if needed, and set:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
On newer Ubuntu, files under /etc/ssh/sshd_config.d/ can override the main config, and cloud images often ship one that re-enables password auth. Check and fix:
grep -r PasswordAuthentication /etc/ssh/sshd_config.d/
Then restart SSH:
sudo systemctl restart ssh
Keep your existing session open and test a fresh login in another terminal. If you locked yourself out, that open session (or your provider's web console) is the way back in.
Step 5: Turn on the firewall
Ubuntu ships ufw, an uncomplicated firewall, disabled. Default-deny everything inbound except SSH:
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status
Allow the SSH rule before enabling, in that order, or you cut your own line. Later, open only what the server actually serves, for example sudo ufw allow 443/tcp for a web server. Everything else stays closed.
Step 6: Turn on automatic security updates
Servers get forgotten. Unattended-upgrades installs security patches on its own so a forgotten server is not also an unpatched one:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Answer Yes at the prompt. The default configuration applies security updates only, which is the right setting: security patches are low-risk, and you still control feature upgrades yourself.
Step 7: Install fail2ban
With password auth off, brute-force attempts cannot succeed, but fail2ban makes attackers go away instead of hammering your logs forever. It watches for repeated failures and temporarily bans the source IP at the firewall:
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
The defaults protect SSH out of the box. Check it is watching:
sudo fail2ban-client status sshd
Give a public server a day and this will show banned IPs. That is the internet background noise you just tuned out.
Verify it
Run through this list from your own machine:
ssh root@203.0.113.10is refused.ssh mason@203.0.113.10works with your key, andssh -o PubkeyAuthentication=no mason@203.0.113.10is refused instead of asking for a password.sudo ufw statusshows active, with only the ports you meant to open.sudo fail2ban-client status sshdshows the jail running.systemctl status unattended-upgradesshows active.
That is the baseline. It does not make a server invincible, but it removes the failure modes that account for most compromised small-business servers: root passwords, open ports, and patches nobody applied. From here, whatever you install on the box starts from solid ground. And if you have servers running right now that never got this treatment, that is a quick job to put right.
Stuck on this, or want it done for you? That's the job.
Email us →