Skip to content

SSH Hardening

All changes below go in /etc/ssh/sshd_config (or a file in /etc/ssh/sshd_config.d/). After editing, validate and restart:

Terminal window
sudo sshd -t # test config for syntax errors
sudo systemctl restart sshd

Always keep an existing SSH session open while testing changes — if you lock yourself out, the open session is your recovery path.


PermitRootLogin no

Force use of a regular user + sudo. Eliminates the most brute-forced username.

PasswordAuthentication no

Key-only authentication. Make sure your key is in ~/.ssh/authorized_keys and working before enabling this.

AllowUsers your-username deployer

Whitelist approach — only listed users can SSH in. Everyone else is rejected before auth is even attempted. Remember to add new users here if they need SSH access.

Port 2222

Not real security (port scanners find it), but cuts down on automated brute-force noise significantly. Update your firewall rules to match:

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

SettingValuePurpose
PubkeyAuthenticationyesEnable key-based auth (usually default)
AuthorizedKeysFile.ssh/authorized_keysDefault key location
ChallengeResponseAuthenticationnoDisable keyboard-interactive auth
KbdInteractiveAuthenticationnoSame as above (newer name)
UsePAMyesKeep PAM enabled for account checks
X11ForwardingnoDisable unless you need remote GUI apps
PermitEmptyPasswordsnoNever allow empty passwords
MaxAuthTries3Lock out after N failed attempts per connection
LoginGraceTime30Seconds before unauthenticated connection is dropped
ClientAliveInterval300Send keepalive every N seconds
ClientAliveCountMax2Drop connection after N missed keepalives

Terminal window
ssh-keygen -t ed25519 -C "your-email@example.com"

Ed25519 is the current recommendation — short keys, fast, strong. Use RSA 4096 only if you need compatibility with old systems.

Terminal window
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@example.com

SSH is strict about file permissions. If these are wrong, key auth silently fails:

~/.ssh/ → 700 (drwx------)
~/.ssh/authorized_keys → 600 (-rw-------)
~/ → 755 (drwxr-xr-x) or stricter

Check with:

Terminal window
ls -la ~/.ssh/
ls -ld ~/

Fail2ban watches auth logs and bans IPs that fail too many times. Essential complement to SSH hardening.

Terminal window
sudo apt install fail2ban
sudo systemctl enable --now fail2ban

Create /etc/fail2ban/jail.local (don’t edit jail.conf directly — it gets overwritten on updates):

[sshd]
enabled = true
port = 2222
maxretry = 3
findtime = 600
bantime = 3600
SettingMeaning
maxretryBan after N failures
findtimeWithin this window (seconds)
bantimeDuration of ban (seconds). Use -1 for permanent.
Terminal window
sudo fail2ban-client status sshd # show jail stats and banned IPs
sudo fail2ban-client set sshd unbanip 1.2.3.4 # unban an IP
sudo fail2ban-client set sshd banip 1.2.3.4 # manually ban an IP

After configuring, verify the state:

Terminal window
# Check which auth methods are active
sudo sshd -T | grep -i -E 'passwordauth|pubkeyauth|permitroot|allowusers|port '
# Check for open SSH port
sudo ss -tlnp | grep sshd
# Check fail2ban is running
sudo fail2ban-client status sshd
Sample hardened sshd_config block
Port 2222
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
UsePAM yes
X11Forwarding no
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers your-username