Use this order
Server hardening is not a race to disable everything. A safe sequence is: create a local key, copy it to the deploy user, prove a second session works, allow SSH in the firewall, enable the firewall, then change SSH policy. Keep the provider console and the original session open throughout.
Generate and copy an Ed25519 key
Run key generation on your own computer, not on the server. Ubuntu recommends Ed25519 as a strong default. Protect the private key with a passphrase and never upload it to the website or repository.
ssh-keygen -t ed25519 -C 'my-laptop'
ssh-copy-id deploy@203.0.113.10
ssh deploy@203.0.113.10
If ssh-copy-id is unavailable, add only the .pub file contents to /home/deploy/.ssh/authorized_keys from the provider console. Never copy the private key. In the new session, run sudo whoami and leave it open.
Enable UFW without losing SSH
Ubuntu's UFW is initially disabled on many images. Add the SSH rule before enabling it. If your SSH service uses a custom port, allow that exact port instead of 22.
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
The final status should include the SSH service and TCP ports 80 and 443. Do not open database, development or application ports to the whole internet unless there is a documented need.
Tighten SSH only after verification
Use a file in /etc/ssh/sshd_config.d on current Ubuntu systems so the change is easy to identify. Check the effective configuration and syntax before reloading. Distribution defaults differ, so review the official OpenSSH guide for your version.
sudoedit /etc/ssh/sshd_config.d/99-aioos-hardening.conf
sudo sshd -t
sudo systemctl reload ssh
sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin|pubkeyauthentication'
A beginner-friendly policy is PubkeyAuthentication yes, PasswordAuthentication no and PermitRootLogin no, but apply it only after the key-based deploy login and sudo have both succeeded. Test a third fresh connection before closing old sessions.
Automatic security updates
Install and enable unattended security updates if the image does not already provide them. Also schedule a regular manual review, because automatic security updates do not manage every application dependency or breaking upgrade.
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
systemctl status unattended-upgrades --no-pager
What I learned
The most dangerous command is often a correct command run in the wrong order. Disabling password login is sensible, but doing it before testing the key can turn a five-minute task into a recovery-console session. I now treat every access-control change as a migration: add the new route, verify it, and only then remove the old route.
Finish line
Open one entirely new terminal and confirm key login, sudo, UFW status and SSH logs. Keep your private key backed up securely. Next, choose and protect the domain name for the site.