Hardening SSH on Ubuntu: Key-Only Auth, Custom Port, and the ssh.socket Gotchas
Standard SSH hardening on Ubuntu (key-only auth, custom port, root login off, firewall + fail2ban) plus two non-obvious traps on Ubuntu 22.10+: ssh.socket socket activation silently overriding the Port directive, and sshd failing after reboot once ssh.socket is disabled because /run/sshd is no longer created.
Hardening SSH on a fresh Ubuntu server involves four standard steps plus two non-obvious gotchas specific to modern Ubuntu (22.10+), where SSH is started through systemd socket activation by default. Standard hardening: 1. Key-only auth — put your public key in `~/.ssh/authorized_keys` (directory mode 700, file mode 600) 2. Move SSH off port 22 via a drop-in file (e.g. `/etc/ssh/sshd_config.d/99-security-hardening.conf`) containing: `Port 2222`, `PermitRootLogin no`, `PasswordAuthentication no`, `PubkeyAuthentication yes` 3. Validate with `sudo sshd -t` and confirm the effective config with `sudo sshd -T | grep -E "^port|^permitrootlogin|^passwordauthentication"` — the `-T` output shows what sshd will actually apply, which catches an overriding directive elsewhere 4. Update the firewall (`ufw allow 2222/tcp`) and point the fail2ban sshd jail at the new port Gotcha 1 — socket activation overrides your Port directive. On Ubuntu 22.10+ `ssh.socket` listens on port 22 and launches sshd on demand, so changing `Port` in sshd_config appears to have no effect or causes port conflicts. Fix: `sudo systemctl stop ssh.socket && sudo systemctl disable ssh.socket`, then restart the ssh service so it binds the port itself. Gotcha 2 — disabling ssh.socket breaks sshd after reboot. The socket unit was what created `/run/sshd` (the privilege separation directory) on boot; without it sshd fails to start with "Missing privilege separation directory". Fix: `echo 'd /run/sshd 0755 root root -' | sudo tee /etc/tmpfiles.d/sshd.conf` so systemd-tmpfiles recreates it every boot. Verify sshd is listening on the new port with `ss -tlnp | grep ssh`. Critically: always open a second terminal (or a detached tmux session) and test `ssh -p 2222 user@host` BEFORE closing your working session — a botched SSH config on a remote VPS with no console access means being locked out. If later connections are reset before key exchange, see SSH kex troubleshooting.