Harden SSH without locking yourself out

Most SSH hardening is three or four lines of config. The hard part is applying them over the same SSH connection they control. Do it in an order where every mistake is still fixable.

Why people lock themselves out

sshd reads its config when it starts or reloads. Your current session keeps running on the old rules, so a bad change looks fine until you log out and try to come back. By then the only way in is your provider's console.

The fix is a habit, not a tool: keep a working session open, check the config before applying it, and test with a brand new connection before you close anything.

Before you change anything

Put your settings in a drop-in file

On Ubuntu and Debian, the first line of /etc/ssh/sshd_config is Include /etc/ssh/sshd_config.d/*.conf. Files there are read in name order, and for each setting sshd uses the first value it finds. So a file with a low number wins over both the main file and later drop-ins, including the 50-cloud-init.conf that many cloud images ship.

sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
# keys only
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no

# no direct root login
PermitRootLogin no

# limits
MaxAuthTries 3
LoginGraceTime 30

# optional: only these users may log in at all
# AllowUsers you deploy

What each one does, and the default if you leave it out:

Check the config before applying it

sshd -t checks the config files and host keys and prints nothing if they are fine. sshd -T also prints the settings sshd will actually use, after every include.

sudo sshd -t
sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|maxauthtries|logingracetime|allowusers)'

The output keywords are lowercase. If a value isn't what you wrote, another file set it first. If you use Match blocks, add the connection you care about so they are applied too:

sudo sshd -T -C user=you,host=your.server.example,addr=203.0.113.10

Reload or restart

On Ubuntu and Debian, the ssh unit runs sshd -t before a reload and before a start. The difference is what happens when that check fails:

sudo systemctl reload ssh

Either way, existing sessions stay up: the unit uses KillMode=process, so only the listening daemon is stopped, not your shell. Prefer reload for config changes. Ubuntu's docs use restart, which is fine once sshd -t passes.

Don't close your old session yet. It survives the reload, so it looks like everything worked. Until a fresh login succeeds, that open session is your only way to fix the config without the provider console.

Test with a fresh connection

From a new terminal on your Mac, connect as you normally would:

ssh -v [email protected]

Look for Authenticated and the publickey method in the verbose output. Then confirm that the things you blocked are blocked:

# should fail with: Permission denied (publickey)
ssh -o PubkeyAuthentication=no [email protected]

# should fail
ssh [email protected]

Only when the good login works and the bad ones fail, close the old session.

If you get locked out

If the fresh login fails and your old session is still open, move the drop-in out of the way and reload:

sudo mv /etc/ssh/sshd_config.d/00-hardening.conf /root/
sudo sshd -t && sudo systemctl reload ssh

If you already closed it, use your provider's web or serial console, log in as a user with a password, and do the same. Some providers can also boot a rescue system where you mount the disk and edit the file. The server's auth log usually says why a login was refused:

sudo journalctl -u ssh -n 50

After SSH is locked down, the next steps are a firewall that leaves your SSH port open (set up UFW safely) and banning repeat offenders (fail2ban for SSH).

Stenvakt applies this without the risk. Its Review shows which of these settings your servers are missing, and Preview shows every line it will change before it runs. Fixes run in safe mode with a snapshot, a rollback timer and a fresh-connection test: if a change cuts off SSH, the server rolls it back by itself. Shared-SSH protection makes sure it never locks out other people's logins. It's a Mac app and isn't out yet: get early access.

Sources

  1. OpenBSD manual: sshd_config(5)
  2. OpenBSD manual: sshd(8) (-t, -T, -C and SIGHUP)
  3. Ubuntu Server docs: OpenSSH server
  4. Ubuntu openssh package (noble): ssh.service unit
Next guideSSH keys with ed25519