SSH is the backbone of remote server administration, yet misconfigured SSH servers remain one of the most exploited attack vectors in 2026. With automated botnets scanning millions of IPs daily, a default SSH setup is essentially an open invitation. In this guide, we’ll walk through 10 essential hardening practices that will dramatically reduce your attack surface and keep intruders out.
1. Disable Root Login
Allowing direct root login over SSH is the single biggest risk. Every attacker tries root first. Disable it immediately.
# /etc/ssh/sshd_config
PermitRootLogin noInstead, log in as a regular user and use sudo for privileged operations. This adds an extra authentication layer even if credentials are compromised.
2. Use SSH Key Authentication Only
Passwords are brute-forceable. SSH keys are not (practically). Generate a strong Ed25519 key pair and disable password auth entirely.
# Generate key (on your local machine)
ssh-keygen -t ed25519 -C "your_email@example.com"
# Copy to server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# Then in sshd_config:
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yesEd25519 keys are faster, smaller, and more secure than RSA. If you’re still using RSA, use at least 4096 bits.
3. Change the Default Port
While security through obscurity isn’t a complete solution, moving SSH off port 22 eliminates 99% of automated scanning bots.
# /etc/ssh/sshd_config
Port 2222Choose a port above 1024 and below 65535. Remember to update your firewall rules and SSH client config accordingly.
# ~/.ssh/config (client side)
Host myserver
HostName 203.0.113.50
Port 2222
User deploy
IdentityFile ~/.ssh/id_ed255194. Implement Fail2Ban
Fail2Ban monitors log files and automatically bans IPs that show malicious behavior. It’s your automated security guard.
# Install
sudo apt install fail2ban
# Create local config
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localConfigure the SSH jail in /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600This bans any IP that fails 3 login attempts within 10 minutes, for 1 hour. For repeat offenders, consider using bantime.increment = true for exponential ban times.
5. Restrict Users and Groups
Limit which users can actually SSH into the server. There’s no reason every system account should have SSH access.
# /etc/ssh/sshd_config
AllowUsers deploy admin
# OR restrict by group
AllowGroups ssh-usersCreate a dedicated SSH group and add only the users who need remote access:
sudo groupadd ssh-users
sudo usermod -aG ssh-users deploy6. Configure Idle Timeout
Abandoned SSH sessions are a security risk. If someone walks away from an unlocked terminal, an idle session is a free pass.
# /etc/ssh/sshd_config
ClientAliveInterval 300
ClientAliveCountMax 2
# Also set login grace time
LoginGraceTime 30This disconnects idle sessions after 10 minutes (300s × 2 checks) and gives users only 30 seconds to authenticate before dropping the connection.
7. Enable Two-Factor Authentication
Combine SSH keys with TOTP (Time-based One-Time Passwords) for true multi-factor authentication.
# Install Google Authenticator PAM module
sudo apt install libpam-google-authenticator
# Run setup as your user
google-authenticatorUpdate PAM configuration in /etc/pam.d/sshd:
auth required pam_google_authenticator.soAnd enable challenge-response in sshd_config:
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactiveNow users need both their SSH key and a TOTP code to log in.
8. Harden the SSH Protocol Settings
Disable weak ciphers, MACs, and key exchange algorithms. Only allow modern, secure options.
# /etc/ssh/sshd_config
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256You can audit your current server configuration using ssh-audit:
# Install and run
pip install ssh-audit
ssh-audit localhostThis tool grades your SSH config and flags any weak algorithms.
9. Set Up UFW Firewall Rules
Use a firewall to restrict SSH access to known IP addresses or ranges.
# Allow SSH only from specific IPs
sudo ufw allow from 203.0.113.0/24 to any port 2222 proto tcp
# Or allow from anywhere (if you need it)
sudo ufw allow 2222/tcp
# Enable the firewall
sudo ufw enable
sudo ufw status verboseFor production servers, whitelist only your office, VPN, or bastion host IPs. Combine this with a VPN like WireGuard for maximum security.
10. Monitor and Audit SSH Access
Hardening is useless without monitoring. Set up proper logging and alerts so you know when something suspicious happens.
# Increase log verbosity
# /etc/ssh/sshd_config
LogLevel VERBOSECheck recent login attempts regularly:
# View successful logins
last -n 20
# View failed attempts
sudo grep 'Failed password' /var/log/auth.log | tail -20
# Count attacks by IP
sudo grep 'Failed password' /var/log/auth.log | \
awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | headFor automated alerting, set up a simple script that emails you on successful logins from new IPs:
#!/bin/bash
# /etc/ssh/notify-login.sh
echo "SSH login: $PAM_USER from $PAM_RHOST at $(date)" | \
mail -s "SSH Login Alert" admin@example.comAdd to /etc/pam.d/sshd:
session optional pam_exec.so /etc/ssh/notify-login.shBonus: The Complete Hardened sshd_config
Here’s a consolidated config bringing all the above together:
# /etc/ssh/sshd_config - Hardened
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
AllowGroups ssh-users
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
PermitTunnel no
LogLevel VERBOSE
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512After making changes, always validate your config before restarting:
sudo sshd -t
sudo systemctl restart sshdImportant: Keep a second SSH session open while testing changes. If you lock yourself out, you’ll still have a way back in.
Wrapping Up
SSH security isn’t a one-time task — it’s an ongoing practice. Start with the basics (disable root, use keys), then layer on additional protections as needed. Run ssh-audit quarterly, review your Fail2Ban logs, and keep OpenSSH updated. A well-hardened SSH server is one of the strongest defenses in your security toolkit.
Got questions or want to share your own SSH hardening tips? Drop a comment below.

Leave a Reply