Skip to content

Hardening SSH

SSH is the front door on nearly every Linux host, and it is continuously scanned and brute-forced from the moment a host gets a public IP. Most of the work of securing it is removing targets rather than defending them: an account that cannot be logged into cannot be guessed.

Work through the controls in order. The first two close the large majority of real-world exposure; the rest narrow what’s left.

10 controls

Every control below changes how you authenticate. Two rules make the whole list safe to apply:

  1. Keep your current session open while you work. If a change locks you out, an already-authenticated session is the way back in.
  2. Test from a second terminal before closing the first. Confirm you can still log in, then close.

Without console or out-of-band access, an SSH misconfiguration on a remote host is not recoverable.

Server-side settings are in /etc/ssh/sshd_config. Many distributions also read drop-in files from /etc/ssh/sshd_config.d/*.conf, and the first matching directive wins — a setting in a drop-in can silently override the one you just edited in the main file. This is why every control here verifies against the running daemon rather than the file you edited.

Reloading, and the Ubuntu socket exception

Section titled “Reloading, and the Ubuntu socket exception”

Most controls here take effect on reload:

Terminal window
sudo systemctl reload ssh # Debian, Ubuntu
sudo systemctl reload sshd # RHEL, Rocky, Alma, Fedora

Ubuntu 22.10 introduced systemd socket activation for SSH, where ssh.socket owns the listener and spawns the daemon per connection. Check which model you are on:

Terminal window
systemctl is-enabled ssh.socket

If that returns enabled, authentication settings still apply to new connections as normal — but anything touching the listener (Port, ListenAddress) is owned by the socket, not sshd_config, and needs systemctl daemon-reload && systemctl restart ssh.socket. See Firewall the SSH port for the details.

Always test with sudo sshd -t before reloading. It catches syntax errors while you still have a working daemon.