If a machine has SSH open to the internet, it is being probed right now — automated scanners work through the entire IPv4 space around the clock, guessing usernames and passwords. A default SSH installation accepts password authentication, which means those guesses can eventually land. Three changes turn SSH from your most-attacked surface into a near-impenetrable entry point.
sudo systemctl status ssh and remove or disable anything you don't need. The best attack surface is the one that isn't there.Move 1: generate a modern key pair
Password authentication can be guessed; key authentication can't be. Generate an Ed25519 key pair — the modern default: small, fast, and strong:
# Generate a modern Ed25519 key pair
ssh-keygen -t ed25519 -C "your-label-here"
# When prompted, set a strong passphrase for the key
# This protects the key even if your private key file is stolen
# The key pair is saved to:
# Private key: ~/.ssh/id_ed25519 (keep this secret)
# Public key: ~/.ssh/id_ed25519.pub (share this freely)
# Copy your public key to a remote server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@remote-server
The passphrase matters: it means a stolen key file alone is still useless.
Move 2: harden the server configuration
Test your key login first — you're about to turn off passwords, and you want a working key before you lock the door behind you. Then edit /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config
# Disable password authentication (use keys only)
PasswordAuthentication no
ChallengeResponseAuthentication no
# Disable root login entirely
PermitRootLogin no
# Allow only specific users
AllowUsers yourusername
# Limit authentication attempts
MaxAuthTries 3
MaxSessions 3
# Restart SSH to apply changes
sudo systemctl restart ssh
Each line closes a door: no passwords to brute-force, no root to target (attackers guess root first, always), an explicit allowlist of who may log in at all, and a hard cap on attempts per connection.
Move 3: make failed guesses expensive with fail2ban
Even with passwords off, the probing traffic is noise you can turn into an automatic blocklist. fail2ban watches the auth log and bans IPs that keep failing:
sudo apt install fail2ban -y
# Create a local configuration (do not edit the original)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
# Under [sshd], set:
# enabled = true
# maxretry = 3
# bantime = 3600 # ban for 1 hour
# findtime = 600 # within a 10-minute window
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Check banned IPs
sudo fail2ban-client status sshd
Run that last command after a day exposed to the internet and watch the ban list fill up — it's a live view of exactly why this chapter exists.
The other eight layers
SSH is one door. A hardened workstation also locks the disk (LUKS), the network (default-deny UFW), DNS, the browser, application behavior (AppArmor), and your backups — and pairs it all with the operating habits that keep the setup tight.