Block brute-force attempts with fail2ban
Install fail2ban, ban addresses that keep failing SSH logins, and check and lift bans, on Ubuntu 24.04 or Debian 12 with ufw.
Put a server on the internet with SSH open and bots will try to log in thousands of times a day. With password logins off, they won't get in. They'll still clutter your logs and burn a little CPU, though. fail2ban watches for repeated failures and bans the address for a while.
This assumes you already use ufw. If not, start with Set up a firewall with ufw.
Install it
apt update
apt install -y fail2ban python3-systemdDon't leave out python3-systemd. Debian 12 doesn't write /var/log/auth.log by default, so fail2ban has to read the systemd journal instead, and without that package the SSH jail has nothing to read and fail2ban won't start.
Configure the SSH jail
Leave jail.conf alone; updates overwrite it. Your settings go in /etc/fail2ban/jail.local:
[DEFAULT]
# Ban for one hour after 5 failures within 10 minutes.
bantime = 1h
findtime = 10m
maxretry = 5
# Add bans to ufw, so they show in `ufw status`.
banaction = ufw
# Never ban yourself. Add your own address or network here.
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24
[sshd]
enabled = true
backend = systemdSwap 203.0.113.0/24 for the address you connect from, or take it out if your address changes a lot.
Restart, and make sure it comes back after a reboot:
systemctl restart fail2ban
systemctl enable fail2banCheck it's working
systemctl status fail2ban --no-pager
fail2ban-client status
fail2ban-client status sshdThe first should say active (running), the second lists sshd as a jail, and the third shows how many failures it's seen and who's banned. Don't be surprised if there are bans within the hour. They also turn up as DENY rules at the top of ufw status.
If you ban yourself
Connect from a different address (or the serial console) and lift it:
fail2ban-client set sshd unbanip 203.0.113.7Longer bans for repeat visitors
The same bots come back. Add these to [DEFAULT] and each repeat ban doubles in length, up to a week:
bantime.increment = true
bantime.maxtime = 1wRestart fail2ban after any change.
If it won't cooperate
- It won't start.
fail2ban-client -ttests the config, andjournalctl -u fail2ban -n 50says why. On Debian 12, a complaint about a missing/var/log/auth.logmeansbackend = systemdisn't set orpython3-systemdisn't installed. - No failures counted for ages. Make sure SSH is logging to the journal:
journalctl -u ssh -n 20. - Bans don't show in
ufw status. Checkbanaction = ufwis in[DEFAULT], and that ufw is actually on.