Blog

Fail2ban explained simply: what it does and how to check it

Jails, bantime, findtime and maxretry, the jail.local file, fail2ban-client status sshd, unbanning an IP: understand fail2ban and check that it protects your VPS.

Équipe Coxios4 min read

  • Security
  • fail2ban
  • SSH
All articles

Open the SSH logs of a VPS exposed to the Internet: you will see hundreds of login attempts a day, with user names like admin, test or ubuntu. These are bots trying passwords in a loop. fail2ban is the tool that shows them the door.

The idea fits in one sentence: fail2ban reads the logs, spots failures, and when the same IP address fails too often, it blocks it in the firewall for a while. Let's see how it works, how to tune it, and above all how to check that it really does its job.

Three pieces: filter, jail, action

fail2ban combines three elements, each in its own folder under /etc/fail2ban/:

  • The filter (filter.d/): regular expressions that recognize a failure line, for example "Failed password for root from 203.0.113.42". There are filters for SSH, nginx, Postfix and dozens of other services.
  • The action (action.d/): what to do with an offending address. By default, a firewall rule (iptables or nftables) that drops its packets.
  • The jail: it ties a filter, a log source and an action together, with its own settings. The sshd jail watches SSH, an nginx-http-auth jail would watch a website's passwords.

bantime, findtime, maxretry

Three settings decide everything. With maxretry = 5, findtime = 10m and bantime = 1h, the rule reads: 5 failures within 10 minutes from the same IP, and it is banned for one hour. When the ban ends, fail2ban releases it on its own.

  • maxretry: the number of failures allowed. Too low and you ban yourself on the slightest typo; 3 to 5 is a good balance.
  • findtime: the time window in which failures are counted. The units m, h and d are accepted.
  • bantime: how long the ban lasts. -1 bans forever, which is rarely a good idea (addresses change hands).

For repeat offenders, bantime.increment = true makes the ban longer each time the same address comes back: one hour the first time, then two, then four, and so on.

Where the configuration lives

Never edit /etc/fail2ban/jail.conf: a package update may overwrite it. Your settings go in /etc/fail2ban/jail.local (or in files under /etc/fail2ban/jail.d/), which are read afterwards and take precedence. On Debian and Ubuntu, the package already enables the sshd jail through jail.d/defaults-debian.conf.

Here is a complete jail.local for SSH. Replace 198.51.100.7 with your static IP address, if you have one: ignoreip lists the addresses that will never be banned.

ini
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
bantime.increment = true
ignoreip = 127.0.0.1/8 ::1 198.51.100.7

[sshd]
enabled = true
# Reads the systemd journal: needed on Debian 12, which has no /var/log/auth.log
backend = systemd
/etc/fail2ban/jail.local. The systemd backend needs the python3-systemd package.
bash
# Check the configuration, then reload
sudo fail2ban-client -t
sudo fail2ban-client reload

Check that it works

A fail2ban that is installed but misconfigured bans nobody, and nothing warns you. Three commands are enough to be sure. First, is the service running, and which jails are active?

bash
sudo systemctl status fail2ban
sudo fail2ban-client status

Then, the details of the SSH jail:

text
$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 2
|  |- Total failed:     143
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 3
   |- Total banned:     27
   `- Banned IP list:   203.0.113.42 192.0.2.77 198.51.100.23
A Total failed stuck at 0 on a server exposed for days is suspicious: the filter is probably not reading the right log.

Finally, if you doubt the filter, fail2ban-regex replays it on the existing logs and counts the matching lines. fail2ban's own log, /var/log/fail2ban.log, shows every ban as it happens.

bash
sudo fail2ban-regex systemd-journal sshd
sudo tail -f /var/log/fail2ban.log

Unban an IP address

It happens: a colleague mistypes their password five times, or it is you. To release the address without waiting for the ban to end:

bash
# In one jail
sudo fail2ban-client set sshd unbanip 203.0.113.42

# In every jail
sudo fail2ban-client unban 203.0.113.42

# Manually ban an address that keeps trying
sudo fail2ban-client set sshd banip 203.0.113.42

What fail2ban does not do

fail2ban cuts the noise and slows down brute-force attacks, but it does not replace SSH key login. If passwords are disabled, those bots never stood a chance anyway: fail2ban simply sends them to waste their time elsewhere. It does not protect against a flaw in a web application either, and an attack spread over thousands of addresses stays under its thresholds.

Also think about services running in Docker: their ports bypass the usual firewall rules, so a jail protecting them has to act on the DOCKER-USER chain.