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

bash
apt update
apt install -y fail2ban python3-systemd

Don'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:

ini
[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 = systemd

Swap 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:

bash
systemctl restart fail2ban
systemctl enable fail2ban

Check it's working

bash
systemctl status fail2ban --no-pager
fail2ban-client status
fail2ban-client status sshd

The 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:

bash
fail2ban-client set sshd unbanip 203.0.113.7

Longer bans for repeat visitors

The same bots come back. Add these to [DEFAULT] and each repeat ban doubles in length, up to a week:

ini
bantime.increment = true
bantime.maxtime   = 1w

Restart fail2ban after any change.

If it won't cooperate

  • It won't start. fail2ban-client -t tests the config, and journalctl -u fail2ban -n 50 says why. On Debian 12, a complaint about a missing /var/log/auth.log means backend = systemd isn't set or python3-systemd isn'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. Check banaction = ufw is in [DEFAULT], and that ufw is actually on.

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.