Fail2ban for SSH

Every public server gets a steady stream of SSH password guesses. Fail2ban watches for them and blocks the addresses that keep failing. It's a useful filter, but it isn't a lock: key-only login is what actually keeps people out.

What fail2ban does

Fail2ban reads log messages, counts failures per IP address, and when one address fails too often in a short window, it adds a firewall rule that drops that address for a while. For SSH, that means bots guessing passwords get blocked after a few tries instead of being able to try thousands of times.

That's all it does. It doesn't make a weak password safe, and it can't see attackers who spread their guesses across many addresses. Treat it as noise reduction on top of key-only auth, not instead of it.

Install it

sudo apt update
sudo apt install fail2ban
sudo systemctl enable --now fail2ban

On Debian and Ubuntu the package already turns on the sshd jail in /etc/fail2ban/jail.d/defaults-debian.conf. Read that file before you add your own settings, so you know what's already set:

cat /etc/fail2ban/jail.d/defaults-debian.conf

On Debian 13 it enables the sshd jail, sets backend = systemd for it, and uses nftables to ban. Older or Ubuntu packages may differ, which is why you look first.

Use jail.local, not jail.conf

/etc/fail2ban/jail.conf holds the defaults and says at the top that you should not modify it. Package upgrades can replace it. Put your changes in /etc/fail2ban/jail.local (or a .local file in jail.d/) instead. Fail2ban reads the .conf files first and lets the .local files override them, so you only write the settings you change.

sudo nano /etc/fail2ban/jail.local
[DEFAULT]
# never ban these: loopback and your own fixed address
ignoreip = 127.0.0.1/8 ::1 203.0.113.7

bantime  = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true
backend = systemd
# port = 2222   # only if sshd listens on a non-standard port

The settings that matter

Read the journal, not auth.log

Fail2ban needs to find sshd's log messages. Older setups wrote them to /var/log/auth.log through rsyslog. Since Debian 12, rsyslog isn't installed by default, so that file may not exist and a jail pointed at it fails to start. sshd's messages are always in the systemd journal.

Setting backend = systemd in the [sshd] section tells fail2ban to read the journal directly. On Debian 13 the package does this already. If your system still has rsyslog and auth.log, either backend works; pick one and stay consistent.

Check the configuration before you reload, then reload:

sudo fail2ban-client -t
sudo fail2ban-client reload

Add your own address to ignoreip before testing. If you test bans by failing logins from your own machine, you will be banned too. Keep a second SSH session open while you change anything, and know how to reach your provider's web console.

Check bans and unban someone

# which jails are running
sudo fail2ban-client status

# failures and banned addresses for the SSH jail
sudo fail2ban-client status sshd

# unban one address from the sshd jail
sudo fail2ban-client set sshd unbanip 198.51.100.23

# or unban it from every jail
sudo fail2ban-client unban 198.51.100.23

status sshd shows "Currently failed", "Total failed", "Currently banned" and the banned IP list. If "Total failed" stays at zero while the journal shows failed logins, fail2ban isn't reading the right log. That usually means the backend setting is wrong.

What it doesn't protect against

With key-only auth in place, fail2ban mostly keeps your logs quieter. That's still worth having. To see what the bots are actually trying, read who tried to log in over SSH.

Stenvakt starts with a read-only Review. It runs a security and health check of every server, and every fix it suggests is shown in a Preview before it runs. Changes to SSH run in safe mode, with a snapshot, a rollback timer and a test over a fresh connection. It's a Mac app and isn't out yet: get early access.

Sources

  1. fail2ban on GitHub: config/jail.conf (defaults and option comments)
  2. Debian fail2ban package: jail.d/defaults-debian.conf
  3. Debian manpages: fail2ban-client(1)
  4. Debian 12 release notes: rsyslog is no longer installed by default
Next guideHarden SSH without locking yourself out