10-Point Security Checklist for a Fresh Ubuntu Server Install
A fresh Ubuntu Server install feels clean. It is also, out of the box, built for convenience rather than for exposure to the internet: root can log in over SSH, password authentication is enabled, no firewall rules are loaded, and security patches arrive only when you ask for them. The distance between "installed" and "safe enough to leave running" is about ten decisions. Most take a minute, and doing them on day one is far easier than cleaning up after a compromise.
Here is the order I use on a new machine, from the first SSH session to the last thing written down before walking away.
1. Create a non-root user first
Log in as root once, create the account you will actually use, give it sudo, then log out of root and stay out.
Run adduser deploy, then usermod -aG sudo deploy. Open a second terminal and confirm you can log in as deploy and run sudo -v. Only close the root session when that works.
From here on: no root logins, no shared accounts, one account per person. Two accounts cost nothing and make the logs readable.
2. Switch to SSH keys, then disable passwords
Generate a key on your own machine (ssh-keygen -t ed25519), copy it over with ssh-copy-id, and check that key login works before changing anything on the server. Then edit /etc/ssh/sshd_config:
- PasswordAuthentication no — password guessing is the most common attack against a public server.
- PermitRootLogin no — root is not a person. Nobody should log in as it.
- PubkeyAuthentication yes — usually implied, but worth stating.
- AllowUsers deploy — optional, and a tidy extra lock.
Validate with sshd -t before reloading, then systemctl reload ssh. Keep one session open while you test a fresh login in another. Know where your provider's console lives before you need it; that is your way back in.
Changing the SSH port cuts bot noise but stops nobody who is actually looking at you. Disabling passwords does.
3. Set the firewall to deny by default
Ubuntu ships ufw, a friendly front end to nftables. Three commands and a check:
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow OpenSSH (or the specific port you use)
Then ufw enable and ufw status verbose. Add 80 and 443 only if you actually serve web traffic. If your provider offers a cloud firewall or security group, keep the two in sync; the most restrictive rule wins, which is what you want but confusing at 2 a.m. For SSH, ufw limit OpenSSH is a small upgrade that throttles repeated connection attempts from one address.
4. Automate security updates
Run apt update and apt full-upgrade once by hand so you start from a patched base. Then let the machine keep itself current: apt install unattended-upgrades, followed by dpkg-reconfigure --priority=low unattended-upgrades. The default configuration applies updates from the Ubuntu security pocket, which is exactly what you want.
Decide now how you will handle kernel updates, which need a reboot. Watch /var/run/reboot-required after upgrades, or set an automatic reboot window in /etc/apt/apt.conf.d/50unattended-upgrades. A patched kernel with a weekly reboot beats a perfectly patched kernel that never restarts.
5. Tighten users, groups, and sudo
Permissions on a server are mostly about who can become root, and what a stolen file is worth to an attacker.
- Give sudo to people who need it, and put rules in files under /etc/sudoers.d rather than editing /etc/sudoers directly. Always use visudo, which checks syntax before saving.
- Use NOPASSWD sparingly. Convenient for automation accounts, dangerous for humans.
- Keep ~/.ssh at 700, and authorized_keys at 600. Home directories should not be world-readable on a multi-user box.
- Remove accounts you don't need; lock ones you'll use later with usermod -L.
On machines holding shared data, set a stricter default umask such as 027 in /etc/login.defs and in the shell profile, so new files arrive without world read access.
6. Look at what's listening, then cut it back
ss -tulpn lists every listening socket and the process behind it. Run it after setup and again after installing anything. If you don't recognise a service, find out what started it before disabling it; systemctl list-unit-files --state=enabled shows what will come back after a reboot.
Ubuntu images carry things you may not need: snapd, printing services on desktop-adjacent builds, LXD or multipath tooling on some cloud images. Disable what you don't use with systemctl disable --now. Fewer services means less attack surface and fewer things to patch.
For brute-force noise, install fail2ban and write a jail in /etc/fail2ban/jail.local using backend = systemd and sensible values for maxretry, findtime, and bantime. Check it with fail2ban-client status sshd. It is a noise filter, not a shield.
7. Set up logs, backups, and a way back in
Know where to look. journalctl -u ssh and /var/log/auth.log record failed and successful logins; a run of failures from one address deserves a look, and so does a single success you cannot explain. logwatch or a central log host is worth adding once you run more than a couple of machines.
Backups belong on a security checklist because the cheapest recovery from ransomware or a careless delete is a copy you still have. restic, borg, or plain rsync over SSH all work. The tool matters less than three rules:
- Keep at least one copy on a different machine, ideally in a different location.
- Test a restore, not just a backup job.
- Keep the backup credentials off the server being backed up.
Finally, record how you get back in: provider console address, a second SSH key stored offline, and who to call if the box won't boot.
The first hour is the cheap hour
None of this takes an afternoon. In order: create your user, add keys, turn off password logins and root access, deny incoming traffic, allow only what you serve, automate updates, trim sudo and file permissions, check what's listening, and confirm that logs and backups actually work.
Then put a reminder in your calendar for a monthly look at patches and a quarterly review of keys and accounts that should no longer exist. A server you understand ten minutes after installing it is a server you can still explain a year later. That is the difference between a clean install and a well-run one.
Photo: Christina Morillo / Pexels






