SSH Hardening: Secure Your Server in 30 Minutes
The minimum viable SSH security config that actually matters. Disable password auth, enforce keys, fail2ban, and sleep better.
Why SSH Hardening Matters
Every day, servers get scanned and compromised via weak SSH configurations. Log into any fresh VPS and run tail -f /var/log/auth.log โ you'll see bots hammering root, admin, ubuntu with password guesses within minutes of the server going live.
SSH hardening isn't optional. It's the first thing you do, before you install any software, before you point DNS. This guide covers what actually reduces risk, with specific configs you can copy-paste.
Before You Start
- You need root or sudo access to the server
- Have a second SSH session open while testing changes โ don't lock yourself out
- Know your current SSH port (default: 22)
1. Use SSH Keys, Not Passwords
Password authentication is fundamentally insecure: it's vulnerable to brute force, credential stuffing, and phishing. SSH keys are asymmetric cryptography โ the private key never leaves your machine, and the server only holds the public half.
Generate a Key (if you don't have one)
# Use Ed25519 โ it's the modern standard
ssh-keygen -t ed25519 -C "your_email@example.com"# Save to default location (~/.ssh/id_ed25519)
# Enter a strong passphrase, not empty
Copy Your Key to the Server
# The easy way
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip# If ssh-copy-id isn't available
cat ~/.ssh/id_ed25519.pub | ssh user@your-server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Verify It Works
# Test key-based auth before disabling passwords
ssh -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes user@your-server-ip
# You should log in without a password prompt
2. Disable Password Authentication
Now that key-based auth works, disable passwords.
sudoedit /etc/ssh/sshd_config
Set these values:
# Disable password authentication entirely
PasswordAuthentication no
ChallengeResponseAuthentication no# Disable root login via SSH
PermitRootLogin no
# Disable empty passwords
PermitEmptyPasswords no
# Only listen on specific interfaces if you don't need all
# ListenAddress 0.0.0.0
# Change default port (optional, but reduces noise by 95%)
Port 2222
Warning: Don't change the port and forget it. Note it somewhere. If you lock yourself out, you need console access to recover.
# Test the config before reloading
sudo sshd -t# Reload SSH (existing sessions stay open)
sudo systemctl reload sshd
3. Configure fail2ban
fail2ban monitors auth logs and temporarily bans IPs that fail too many authentication attempts. It's not a substitute for good security, but it reduces noise and automated attacks.
Install
# Ubuntu/Debian
sudo apt update && sudo apt install fail2ban -y# CentOS/RHEL
sudo yum install fail2ban -y
Configure
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudoedit /etc/fail2ban/jail.local
Set these values in [sshd] section:
[sshd]
enabled = true
port = 2222
maxretry = 3
findtime = 10m
bantime = 1h
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Check Status
sudo fail2ban-client status sshd
# Shows banned IPs and current rules
4. Limit SSH Access by User
Only specific users should be able to SSH in. Add an allow list.
# In /etc/ssh/sshd_config
AllowUsers deploy admin backupuser
Or allow only users in a specific group:
# Create an sshusers group
sudo groupadd sshusers
sudo usermod -aG sshusers deploy
sudo usermod -aG sshusers admin# In /etc/ssh/sshd_config
AllowGroups sshusers
5. Use a Restricted Authorized Keys File
Your users' authorized_keys files can include options that restrict what commands are allowed, forward ports, and limit source IPs.
# On the server, edit a specific user's authorized_keys
sudoedit /home/deploy/.ssh/authorized_keys# Add restrictions before the key
from="203.0.113.0/24",no-pty,no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAA...
This example restricts that key to connections from the 203.0.113.0/24 subnet, disables TTY, and disables agent/X11 forwarding.
6. Harden the SSH Daemon Further
sudoedit /etc/ssh/sshd_config
Add or modify these:
# Use modern key exchange
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org# Use modern ciphers
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
# Use modern MACs
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Disable unused authentication methods
HostbasedAuthentication no
GSSAPIAuthentication no
# Disable .rhosts (legacy)
IgnoreRhosts yes
# Log more detail
LogLevel VERBOSE
# Disable connection multiplexing for sensitive servers
DisableForwarding yes
Test and reload:
sudo sshd -t && sudo systemctl reload sshd
7. Set Up SSH Certificates (Advanced)
For teams managing many servers, SSH certificates eliminate the need to distribute and update public keys. This is how GitHub, GitLab, and major cloud providers handle SSH access at scale.
The setup requires a CA (Certificate Authority) key, signing server keys, and distributing the CA public key to servers. It's more complex but scales better and allows time-limited access.
This is beyond this guide's scope, but worth researching if you're managing more than 5 servers.
Verification Checklist
Run through this before declaring the server "done":
- [ ] Can I SSH in with my key from a new location? (Test it)
- [ ] Does password authentication fail? (
ssh -o PreferredAuthentications=password ...) - [ ] Does root login fail? (
ssh root@server) - [ ] Does fail2ban ban after 3 failed attempts? (Test from a throwaway IP or with a friend)
- [ ] Are unused auth methods disabled?
- [ ] Is the SSH port changed (if configured)?
- [ ] Is the second SSH session still open? (Don't close it until everything works)
- Firewall: Configure a firewall (ufw, iptables, or cloud security groups) to allow only necessary ports
- Updates: Keep the OS and SSH package updated (
apt update && apt upgrade) - Monitoring: Log and monitor SSH access โ know who's logging in and when
- Backup access: Have a recovery plan (console access, rescue mode) if you break SSH
What This Doesn't Cover
SSH hardening is necessary but not sufficient:
Quick Recovery if Locked Out
If you break SSH and get locked out:
1. Access the server console (most providers offer this)
2. Mount the disk
3. Edit /etc/ssh/sshd_config to restore working settings
4. Restart SSH
Don't let the config stop you from hardening โ just always keep a working session open while testing.
Rather than DIY? Let OpsHelp handle everything.
Managed hosting with support, security, backups, and monitoring โ from ยฃ50/mo.