Secure SSH with Fail2ban and Key-Only Logins on Ubuntu
Harden the most exposed part of your VPS by switching SSH to keys only, tightening the daemon config, and automatically banning repeated login abuse.
How to confirm SSH key access, disable password logins safely, add a small set of safer SSH defaults, and configure Fail2ban without locking yourself out.
New VPS owners, self-hosters, and anyone who still sees constant SSH password probes in logs.
Changing SSH settings before key login is tested can cut off your only access. Verify first, then harden.
Before you begin
- An Ubuntu server you can already reach over SSH.
- A non-root sudo user on the server.
- An SSH keypair on your local machine.
- Access to your VPS provider console in case you need recovery.
SSH is the front door to most Linux servers. That makes it one of the first things attackers scan, brute-force, and abuse. The goal here is not perfect security. It is a clean, practical baseline that removes easy wins for attackers and lowers noise in your logs.
Why this hardening step matters
Password-based SSH logins are easy to understand, but they are also easy to target. Bots constantly try common usernames and weak passwords on internet-facing servers. Key-only login is far stronger because the private key stays on your device and is not something a bot can guess. Fail2ban adds another layer by watching authentication logs and temporarily banning IPs that keep failing.
Step 1: Verify SSH key access before changing anything
On your local machine, generate a key if you do not already have one:
ssh-keygen -t ed25519 -C "your-name@your-device"Copy the public key to the server:
ssh-copy-id youruser@your-server-ipIf ssh-copy-id is unavailable, copy it manually:
cat ~/.ssh/id_ed25519.pub
ssh youruser@your-server-ip
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysOpen a second terminal and test a new login before touching the SSH config:
ssh youruser@your-server-ipIf the new login works without asking for the server account password, you are ready. Keep your original session open during the whole process so you have a recovery shell if a change goes wrong.
Step 2: Tighten the SSH daemon settings
Back up the existing SSH server config:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bakEdit the config file:
sudo nano /etc/ssh/sshd_configMake sure these settings exist and are not duplicated in conflicting ways:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
UsePAM yes
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2If you changed the SSH port previously, keep that setting consistent with your firewall and Fail2ban config. Before restarting, validate the syntax:
sudo sshd -tIf the test returns no errors, reload SSH:
sudo systemctl reload sshOpen another fresh terminal and confirm that key login still works. Do not close your original session until this test succeeds.
Step 3: Allow SSH through UFW and enable the firewall
If UFW is not already in use, add the OpenSSH rule first:
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verboseIf you use a custom SSH port, allow that exact port instead:
sudo ufw allow 2222/tcpDo not enable UFW until the matching SSH rule is in place, or you can block your own connection.
Step 4: Install and tune Fail2ban
Install the package:
sudo apt update
sudo apt install fail2ban -yCreate a local jail config instead of editing the package defaults:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.localFind the [sshd] section and make sure it is enabled. A practical starting point looks like this:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1hIf you use a custom SSH port, change port = ssh to that port number. Then restart and check status:
sudo systemctl enable --now fail2ban
sudo systemctl restart fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshdYou should see the sshd jail listed and active. If repeated failures come from the same IP, Fail2ban will add a temporary ban.
Expected outcome and verification
Run these checks after setup:
ssh youruser@your-server-ip
sudo ss -tulpn | grep ssh
sudo systemctl status ssh --no-pager
sudo systemctl status fail2ban --no-pager
sudo fail2ban-client status sshd
sudo journalctl -u ssh -n 50 --no-pagerA healthy result usually means:
- Your SSH login works with a key.
- Password login attempts are rejected.
- Fail2ban shows the
sshdjail as active. - The firewall allows only the SSH access you intended.
Troubleshooting common problems
You cannot log in after disabling passwords.
Use the VPS console, restore /etc/ssh/sshd_config.bak, and confirm your public key is in the correct user account’s authorized_keys file.
sudo sshd -t shows a config error.
Check for duplicate directives, spelling mistakes, or settings placed inside the wrong block.
Fail2ban says the SSH jail is inactive.
Confirm the log backend matches your system. On modern Ubuntu, backend = systemd is often the right choice.
You locked yourself out with UFW.
Use your provider console or rescue mode, add the SSH allow rule, and only then re-enable the firewall.
What to do next
Once SSH access is hardened, the next easy win is keeping security patches moving automatically. Continue with Set Up Automatic Security Updates with unattended-upgrades.
