Why SSH Hardening Matters
If your Linux server is connected to the internet and running SSH on port 22, it is being scanned and probed by automated bots — often within minutes of going online. Default SSH configurations prioritize compatibility over security, which means there are several quick wins you can implement right now to dramatically reduce your attack surface.
Important: Always keep a second active SSH session open while making configuration changes. If something breaks, you'll still have access to revert it.
Step 1: Use SSH Key Authentication (and Disable Passwords)
Password-based SSH authentication is vulnerable to brute-force attacks. Key-based authentication is cryptographically far stronger.
Generate a key pair on your local machine:
ssh-keygen -t ed25519 -C "your_email@example.com"
Copy the public key to your server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your_server_ip
Disable password authentication in /etc/ssh/sshd_config:
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
Step 2: Change the Default SSH Port
Port 22 is the first port bots scan. Changing it won't stop a determined attacker, but it eliminates the vast majority of automated noise and log spam.
# In /etc/ssh/sshd_config
Port 2222 # or any unused port above 1024
Remember to update your firewall rules and your SSH client config (~/.ssh/config) to use the new port.
Step 3: Disable Root Login
Root has unlimited privileges. Direct root SSH access is a significant risk — even with key auth. Create a dedicated user and use sudo instead.
# In /etc/ssh/sshd_config
PermitRootLogin no
Step 4: Restrict SSH Access to Specific Users
Use AllowUsers or AllowGroups to create an explicit whitelist of who can SSH in:
AllowUsers deployer alice
# or
AllowGroups sshusers
Step 5: Set Idle Timeout
Automatically disconnect sessions that have been idle too long:
ClientAliveInterval 300
ClientAliveCountMax 2
This disconnects inactive sessions after approximately 10 minutes (300 seconds × 2 checks).
Step 6: Limit Authentication Attempts
MaxAuthTries 3
LoginGraceTime 20
This limits brute-force attempts per connection and gives attackers only 20 seconds to authenticate.
Step 7: Install and Configure fail2ban
fail2ban monitors log files and automatically bans IP addresses that show signs of malicious activity (e.g., repeated failed login attempts).
sudo apt install fail2ban # Debian/Ubuntu
sudo systemctl enable fail2ban --now
Create a local jail config at /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222 # use your custom port
maxretry = 3
bantime = 3600 # ban for 1 hour
findtime = 600
Step 8: Enable a Firewall (UFW)
Only allow the ports you actually need:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp # SSH on your custom port
sudo ufw allow 80/tcp # HTTP (if needed)
sudo ufw allow 443/tcp # HTTPS (if needed)
sudo ufw enable
Hardening Checklist Summary
- ✅ SSH keys enabled, password auth disabled
- ✅ Root login disabled
- ✅ Default port 22 changed
- ✅ AllowUsers / AllowGroups configured
- ✅ Idle timeout set
- ✅ MaxAuthTries and LoginGraceTime configured
- ✅ fail2ban installed and active
- ✅ UFW firewall enabled with minimal open ports
Apply Your Changes
After editing /etc/ssh/sshd_config, validate your config and restart SSH:
sudo sshd -t # test config for errors
sudo systemctl restart ssh
Final Thoughts
Security is a layered effort — no single step is a silver bullet. But implementing all of the above significantly raises the cost for any attacker targeting your server. Combine these SSH hardening steps with regular system updates, monitoring, and least-privilege principles, and you'll have a much more defensible Linux machine.