L9. SSH Hardening: Keys, Config and Fail2Ban
Course outlineLesson 9 of 20
SSH is the primary way administrators access Linux servers, which makes it a top target for attackers. Learn how to replace password authentication with key pairs, harden sshd_config, and use Fail2Ban to block brute-force attempts automatically.
How SSH Works
SSH (Secure Shell) creates an encrypted tunnel between your local machine and a remote server. When you type ssh user@server, a few things happen behind the scenes:
- Your client connects to port 22 (by default) on the remote host
- The server presents its host key so your client can verify it is the real server
- Both sides negotiate encryption algorithms
- The server authenticates you (password, key, or another method)
- You get a shell session over an encrypted channel
Every step in this process has security implications, and most of them can be tuned through a single configuration file.
Password Authentication vs Key-Based Authentication
The Problem with Passwords
Password-based SSH is simple to set up, but it opens the door to brute-force attacks. Automated scanners continuously probe internet-facing servers on port 22, trying thousands of username and password combinations per minute. Rate limiting reduces repeated attempts; use protected private keys and a tested authentication policy.
How SSH Keys Work
SSH key authentication uses a pair of cryptographic keys:
| Component | Location | Purpose |
|---|---|---|
| Private key | Your local machine (~/.ssh/id_ed25519) | Proves your identity (never share this) |
| Public key | Remote server (~/.ssh/authorized_keys) | Verifies signatures from the private key |
Generating a Key Pair
# Generate an Ed25519 key pair (recommended over RSA for new setups)
ssh-keygen -t ed25519 -C "yourname@workstation"# You will be prompted for a file location and a passphrase
# Always set a passphrase: it encrypts the private key at rest
Copy the public key to the remote server:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@remote-serverThis appends your public key to ~/.ssh/authorized_keys on the server. After this, you can log in without a password.
Hardening sshd_config
The SSH daemon's configuration lives at /etc/ssh/sshd_config. Every setting below reduces your attack surface.
Disable Root Login
# /etc/ssh/sshd_config
PermitRootLogin noEven if an attacker guesses a password, they cannot log in directly as root. Administrators should log in with a normal account and escalate with sudo.
The upstream PermitRootLogin default is prohibit-password, which still permits root public-key login; no is an explicit stricter choice. Distribution configuration can override upstream defaults.
Disable Password Authentication
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickeyConfirm a second key-based session first. PasswordAuthentication no alone does not disable keyboard-interactive authentication. ChallengeResponseAuthentication is a deprecated alias of KbdInteractiveAuthentication. The example enforces public-key authentication; adapt it if your approved design uses keyboard-interactive MFA.
Change the Default Port
Port 2222Changing the port does not stop a determined attacker, but it drops the volume of automated scans dramatically. Think of it as reducing noise, not adding real security.
Additional Hardening Options
# Limit login attempts per connection
MaxAuthTries 3# Detect an unresponsive client (not an idle human user)
ClientAliveInterval 300
ClientAliveCountMax 3
# Restrict which users can log in via SSH
AllowUsers deploy monitor
# Disable X11 forwarding unless you need it
X11Forwarding no
ClientAliveCountMax 0 disables connection termination; alive probes are not an interactive user inactivity timer. Keep the current session open, confirm console recovery access, and validate before reloading:
sudo sshd -t # Test for syntax errors
sudo sshd -T # Inspect effective configuration; use -C for Match contexts
# Reload the service for your distribution (ssh or sshd), then test a second login
Fail2Ban: Automated Brute-Force Protection
Fail2Ban monitors log files for repeated failed login attempts and temporarily blocks offending IP addresses using firewall rules.
Installing Fail2Ban
# Debian/Ubuntu
sudo apt install fail2ban# RHEL/CentOS
sudo dnf install fail2ban
Basic Configuration
Create a local override file (never edit the main config directly):
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localKey settings in /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222 # Match your SSH port
maxretry = 5 # Ban after 5 failures
findtime = 600 # Within a 10-minute window
bantime = 3600 # Ban for 1 hour
Managing Fail2Ban
# Start and enable the service
sudo systemctl enable --now fail2ban# Check which IPs are currently banned
sudo fail2ban-client status sshd
# Manually unban an IP
sudo fail2ban-client set sshd unbanip 192.168.1.50
Putting It All Together
A hardened SSH setup combines all three layers:
- Key-only authentication removes the password attack vector
- sshd_config hardening limits who can log in and how
- Fail2Ban blocks IPs that still attempt brute-force scans
No single measure is enough on its own. Defense in depth applies to SSH just as it does to any other security domain.
References
- ✓SSH key pairs use public-key cryptography: the private key never leaves your machine, and the public key goes on the server
- ✓Disable password and keyboard-interactive authentication and explicitly require publickey when key-only access is intended
- ✓PermitRootLogin no forces administrators to use a regular account and escalate with sudo
- ✓Fail2Ban monitors logs and automatically bans IPs that exceed a failed-login threshold
1. What is the primary security benefit of disabling password authentication in sshd_config?
2. Which file on the remote server stores the public keys authorized to log in as a specific user?
3. What does Fail2Ban do when it detects repeated failed SSH login attempts from an IP address?