SSH Hardening
Secure SSH configuration for Debian
This page is a practical SSH hardening reference for Debian servers. Goal: reduce attack surface, enforce strong authentication, and prevent lockouts by validating changes safely.
1) Baseline checks
Know what you are changing
-
Show SSH server version
sshd -V 2>&1 || true ssh -V -
Show effective SSH configuration
sudo sshd -T -
Check current listening ports
sudo ss -lntp | grep -E ':(22|2222)\b' || true -
Confirm active service
systemctl status ssh --no-pager
2) Use key-based authentication
Disable passwords after verification
-
Create a key on your client (recommended: ed25519)
ssh-keygen -t ed25519 -a 64 -f ~/.ssh/id_ed25519 -
Copy public key to server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com -
Manual install (server side)
mkdir -p ~/.ssh chmod 700 ~/.ssh cat id_ed25519.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
Important: keep at least one working SSH session open when testing changes to avoid lockouts.
3) Harden sshd_config
Safe defaults (defensive)
Edit the SSH server config:
sudo vi /etc/ssh/sshd_config
Minimal hardening example (adjust the AllowUsers/AllowGroups for your environment):
# --- Authentication ---
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
# --- Limit access ---
AllowUsers youradminuser
# Or:
# AllowGroups sshusers
# --- Reduce noise / brute-force window ---
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
# --- Security / hygiene ---
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
PermitUserEnvironment no
PrintMotd no
Notes:
- Disabling passwords is only safe after you verified key login works.
- Avoid custom cipher/KEX lists unless you have a strict compliance need. Modern OpenSSH defaults are strong.
- If you need port changes, do it together with firewall updates and keep an active session open.
4) Validate before restart
Prevent lockouts
-
Config syntax test
sudo sshd -t -
Show which config files are included
sudo sshd -T | head -n 60 -
Reload safely
sudo systemctl reload ssh -
Test new login in a second terminal
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no user@server.example.com
5) Firewall notes
Only allow what you need
Example with UFW (adjust your port):
sudo ufw allow 22/tcp
sudo ufw status verbose
If you expose SSH to the internet, combine with:
- Fail2Ban (rate-limiting and bans)
- Allowlist by source IP when possible
- Strong keys and no password auth
6) Quick audit checks
Confirm behavior
-
Auth logs
sudo journalctl -u ssh --no-pager -n 200 -
Last SSH logins
last -a | head -n 25 -
Show loaded keys in the running daemon (sanity)
sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|allowusers|allowgroups)\b'