How to Harden SSH on Linux: A Sysadmin Runbook

by Liam Foster

SSH is the most attacked service on the internet. Full stop.

I've watched honeypot logs. The noise is relentless: credential stuffing, key reuse, old protocol versions, default ports screaming "try me." Yet most Linux deployments ship with SSH wide open. Not because sysadmins are careless—because nobody tells them which changes actually matter versus security theater.

This is how to harden SSH on Linux without breaking deployments. Tested on Ubuntu 22.04 LTS and Rocky 9. Your mileage may vary on older distributions.

Disable Password Authentication Entirely

Password auth is the weakest link. Users pick bad passwords. You know this. They reuse them. Attackers know this too.

Switch to SSH keys only. Full stop.

Edit /etc/ssh/sshd_config:

PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no

Restart SSH:

sudo systemctl restart sshd

Gotcha: Test the connection before you log out. Open a second terminal, SSH in, verify you can authenticate with your key. If you lock yourself out, you'll need console access or a reboot.

Disable Root Login

Root login over SSH is a magnet for brute force. Disable it:

PermitRootLogin no

Users can still sudo once they're in. This forces attackers to guess both a username and a password or key—and you've already killed password auth, so they're stuck.

Change the Default Port

Port 22 is the first thing every scanner hits. Moving to a non-standard port (say, 2222) cuts automated attack traffic by ~90%.

Port 2222

Update your firewall:

sudo ufw allow 2222/tcp
sudo ufw delete allow 22/tcp

Not a silver bullet: This stops script-kiddies, not determined attackers. But it's free noise reduction. I always do it.

Restrict Protocol Version

SSH protocol version 1 is dead. Use version 2 only:

Protocol 2

If you're on a modern Linux (anything post-2010), this is already the default. Check:

grep -i protocol /etc/ssh/sshd_config

If it says 1,2 or just 1, you have a problem.

Tighten Cipher and Key Exchange Settings

Weak ciphers are a slow burn—they don't cause immediate breaches, but they're a liability in audits and forensics.

Add these to sshd_config:

Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
HostKeyAlgorithms ssh-ed25519

These choices prioritize speed and security. Ed25519 keys are faster and stronger than RSA-2048. If you have older clients that can't speak these algorithms, they won't connect—so test first.

Limit Authentication Attempts

Brute force is loud but effective. Slow it down:

MaxAuthTries 3
MaxSessions 5

Three failed attempts and the connection closes. This makes dictionary attacks impractical.

Disable Unused Features

SSH has features you probably don't use. Turn them off:

X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
GatewayPorts no

If you need X11 forwarding for a specific user, enable it per-user in a Match block instead of globally.

Use AllowUsers or AllowGroups

Whitelist who can SSH in. Don't blacklist—that's a losing game.

Create a group:

sudo groupadd ssh-users
sudo usermod -a -G ssh-users alice
sudo usermod -a -G ssh-users bob

Then in sshd_config:

AllowGroups ssh-users

Now only members of ssh-users can authenticate. New user? Add them to the group. No more scattered DenyUsers rules.

Enable Login Grace Time and Timeout

Drop idle connections and enforce timeouts:

LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2

This closes the connection if the client doesn't complete authentication within 30 seconds, and terminates idle sessions after 10 minutes (300 seconds × 2 checks).

Set Up Logging and Monitoring

Hardening without visibility is half-baked. Enable verbose logging:

SyslogFacility AUTH
LogLevel VERBOSE

Check /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (RHEL/Rocky) for failed attempts:

sudo tail -f /var/log/auth.log | grep sshd

Watch for patterns. A single IP making 50 failed attempts in an hour is noise. Fifty IPs each making one attempt is reconnaissance.

The Checklist

Before you restart SSH:

  • Edit /etc/ssh/sshd_config
  • Add or modify: PasswordAuthentication no, PermitRootLogin no, Port 2222
  • Add ciphers, key exchange, and MAC settings
  • Set MaxAuthTries 3, MaxSessions 5
  • Disable unused features (X11, forwarding, tunnels)
  • Create ssh-users group and add users
  • Set LoginGraceTime 30, ClientAliveInterval 300, ClientAliveCountMax 2
  • Enable LogLevel VERBOSE
  • Validate syntax: sudo sshd -t
  • Open a second terminal and test SSH with key auth
  • Confirm you can sudo if needed
  • Only then: sudo systemctl restart sshd
  • Tail the logs and watch for errors

Validate Your Changes

Before restart, check syntax:

sudo sshd -t

If it says nothing, you're good. If it complains, fix the typo and try again.

After restart, verify the service is running:

sudo systemctl status sshd

Then test from a client:

ssh -v -p 2222 alice@your-server

The -v flag shows you exactly what's happening. You should see your key being offered and accepted.

One More Thing: Key Rotation

Hardening SSH is not a one-time job. Rotate your host keys every 12 months. Rotate user keys when people leave. Check /etc/ssh/ssh_host_* for modification dates:

ls -la /etc/ssh/ssh_host_*

If they're older than a year, regenerate them:

sudo ssh-keygen -A
sudo systemctl restart sshd

What to Do Tomorrow

Pull up sshd_config on your production servers. If you see PasswordAuthentication yes, PermitRootLogin yes, or default port 22, you're exposed. Start with password auth and root login—those two changes alone cut your attack surface by 80%.

Test in a staging environment first. SSH hardening is one of the few security changes where a mistake locks you out immediately, so practice the checklist. If your server is also running sluggishly under load, it may be worth reviewing how to speed up a slow Windows 11 PC if any of your management machines are on Windows—a laggy workstation makes remote administration harder than it needs to be.

Once you've hardened SSH on one server, automate it. Ansible, Puppet, or even a shell script—make it repeatable so the next server gets the same treatment without thinking. For teams deciding on a broader infrastructure stack, the comparison on storehabit.com is a reminder that platform choices upstream can affect what you're ultimately responsible for securing.

SSH is your front door. Make it count.