SSH hardening: securing remote access
SSH is how you get into your server. It’s also how attackers try to get in. Default SSH configuration works but leaves room for improvement. A few changes make the difference between a server that gets brute-forced daily and one that shrugs off automated attacks.
Key-based authentication
Passwords get brute-forced. Keys don’t. Generate a key pair:
ssh-keygen -t ed25519 -C "upi@workstation"
Copy the public key to your server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub upi@server
Test that key-based login works before disabling passwords.
Disable password authentication
Edit /etc/ssh/sshd_config:
PasswordAuthentication no
PubkeyAuthentication yes
Restart SSH:
sudo systemctl restart sshd
Keep your current session open while you test the new connection. Locking yourself out is easy when you change SSH settings.
Disable root login
Root should never log in directly via SSH. Edit /etc/ssh/sshd_config:
PermitRootLogin no
Use a regular user and sudo instead. This gives you an audit trail and prevents the most commonly targeted account from being directly accessible.
Change the default port
This is security through obscurity, but it cuts down the noise in your logs dramatically. Pick a high port:
Port 2222
Update your SSH client config (~/.ssh/config) to match:
Host myserver
HostName server.example.com
Port 2222
User upi
Then connect with ssh myserver instead of remembering the port.
Limit users and groups
Only allow specific users to SSH in:
AllowUsers upi admin
# or
AllowGroups sshusers
This prevents service accounts and other system users from being SSH targets.
Set connection timeouts
Idle sessions are a risk. Set timeouts:
ClientAliveInterval 300
ClientAliveCountMax 2
This disconnects idle sessions after 10 minutes (300 seconds × 2).
Rate limiting with fail2ban
Install fail2ban:
sudo apt install fail2ban
Create a local config:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
This bans an IP for 1 hour after 3 failed attempts within 10 minutes.
Start it:
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Check banned IPs:
sudo fail2ban-client status sshd
SSH agent forwarding
If you need to hop through a bastion host, agent forwarding lets you use your local keys on the remote server:
ssh -A upi@bastion
Use this carefully. Anyone with root on the bastion can use your forwarded agent. For production, consider ProxyJump instead:
ssh -J bastion destination
ProxyJump creates a direct tunnel without exposing your agent.
Two-factor authentication
For extra security, set up TOTP with Google Authenticator:
sudo apt install libpam-google-authenticator
google-authenticator
Follow the prompts to set up the QR code, then configure PAM and sshd to require it. This combines something you have (the TOTP token) with something you know (your key passphrase) or have (your SSH key).
Auditing SSH access
Check who’s currently logged in:
who
w
See recent login attempts:
last
lastb # failed attempts
Monitor auth log in real time:
sudo tail -f /var/log/auth.log
Common mistakes
Disabling password auth before testing key auth. Always verify key-based login works first. Keep your current session open.
Locking yourself out with PermitRootLogin. If root is your only account with sudo, and you disable root login, you’re stuck. Make sure you have a regular user in the sudo group first.
Not restarting sshd. Config changes don’t take effect until you restart the service.
Remarks
SSH hardening is one of the first things you should do on any new server. Key-based auth, no root login, fail2ban, and a non-standard port handle the majority of threats. The rest is defense in depth. Every server I’ve set up gets these changes before anything else goes on it.
Related Posts
Vim survival guide for Linux admins
The minimum vim knowledge you need to survive on a Linux server. Editing config files without wanting to throw your keyboard.
Linux memory management: free, vmstat, and /proc
Understanding how Linux uses memory. Reading free correctly, using vmstat, and what /proc/meminfo actually tells you.
tmux: terminal multiplexing made simple
Using tmux to manage terminal sessions. Panes, windows, and why your SSH sessions should survive disconnects.