This is the baseline we apply to our own machines. It is not exhaustive and it is not a compliance programme — it is the ten minutes of work that removes the overwhelming majority of automated attacks against a new host.
Create a user and stop using root
Add an unprivileged account, put your public key on it, and confirm you can log in as that user in a second terminal before you touch the SSH config. Locking yourself out of a fresh box is a rite of passage, but you can skip it.
adduser deploy
usermod -aG sudo deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.sshKey-only SSH
Disable password authentication and root login outright. Password auth is the single biggest source of noise in any server log, and turning it off makes brute-force attempts structurally impossible rather than merely slow.
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication noA default-deny firewall
nftables ships with Ubuntu and needs no extra packages. Accept established connections, loopback, SSH and whatever your service actually listens on. Drop everything else. Write the rules to disk so they survive a reboot — a firewall that does not come back up is worse than none, because you will assume it has.
Automatic security updates
Install unattended-upgrades and leave it on the security pocket only. The argument against automatic updates is unplanned restarts; the argument for is that unpatched hosts are how most compromises begin. Security-only updates are the compromise worth making.
fail2ban for what remains
With password auth disabled, fail2ban is doing far less work than people assume — but it still trims log noise and catches application-layer abuse. Enable the sshd jail and any jail matching a service you actually expose.
Then check it
Scan yourself from outside. An open port you forgot about is the most common finding on a "hardened" box, and it takes thirty seconds to rule out.
Handles hardening, disclosure and the retention policy. Would rather publish the boring specifics than a reassuring summary.