Where to start First steps track · 15 stages
Linux Labs

fail2ban

7 min Ubuntu 24.04 · fail2ban 1.0

Log-based banning — protecting SSH and services from brute force; jails, status, unban.

Cheat sheet

4 commands Printable version
  • sudo fail2ban-client status jails
  • sudo fail2ban-client status sshd banned IPs
  • sudo fail2ban-client set sshd unbanip 1.2.3.4 unban
  • sudo fail2ban-regex /var/log/auth.log sshd test a filter
  • jail.local: bantime, findtime, maxretry, ignoreip, backend

Overview

fail2ban reads service logs, spots signs of an attack (for example, failed SSH logins), and temporarily bans the IP through the firewall. The fail2ban service runs under systemd.

bash
systemctl status fail2ban
sudo fail2ban-client status        # list of active jails
sudo fail2ban-client status sshd   # sshd jail details (banned IPs)

Configuration

Setup

Don't edit jail.conf — create jail.local (it survives package updates):

ini
# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h          # how long to ban for (accepts 10m, 1h, 1d)
findtime = 10m         # the window over which attempts are counted
maxretry = 5           # how many failures before a ban
ignoreip = 127.0.0.1/8 10.0.0.0/24    # allowlist (your own networks!)
backend  = systemd     # on Ubuntu, SSH logs are often in journald

[sshd]
enabled = true

[recidive]             # ban repeat offenders for a long time
enabled  = true
bantime  = 1w
findtime = 1d
maxretry = 5
bash
sudo systemctl restart fail2ban

Your own jail/filter

For your own service: a filter (a regex with an <HOST> group) plus a jail:

ini
# /etc/fail2ban/filter.d/myapp.conf
[Definition]
failregex = ^.*authentication failed from <HOST>.*$

# /etc/fail2ban/jail.local
[myapp]
enabled  = true
logpath  = /var/log/myapp/access.log
maxretry = 4

Test the regex before enabling it: fail2ban-regex <log> <filter> (shows how many matches it caught).

File order

fail2ban reads jail settings in order, and the last value wins:

  1. jail.conf — from the package, do not edit;
  2. jail.d/*.conf — alphabetically, defaults-debian.conf among them;
  3. jail.local;
  4. jail.d/*.local — alphabetically.

maxretry = 6 in jail.d/aa.conf, 4 in jail.local and 3 in jail.d/zz.local give 3. fail2ban-client -d prints the result for a jail:

text
student@ubuntu:~$ sudo fail2ban-client -d | grep "'sshd', '"
['set', 'sshd', 'maxretry', 3]
['set', 'sshd', 'findtime', '10m']
['set', 'sshd', 'bantime', '10m']
['set', 'sshd', 'addignoreip', '127.0.0.1/8', '192.0.2.20']

An error in any file keeps the service from starting — fail2ban-client -d shows it too.

What Ubuntu sets

On the lab machine the fail2ban service is off. The package ships jail.d/defaults-debian.conf:

ini
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
backend = systemd

[sshd]
enabled = true

backend = systemd means the jail reads the systemd journal and needs no logpath. fail2ban-client status sshd shows what it looks for: Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd (+ means "or"; on Ubuntu 24.04 the service is called ssh.service, and the lines are found by _COMM=sshd).

A ban is an address in a set of the inet f2b-table table, and the rule answers with reject:

text
table inet f2b-table {
	set addr-set-sshd {
		type ipv4_addr
		elements = { 192.0.2.20 }
	}
	chain f2b-chain {
		type filter hook input priority filter - 1; policy accept;
		tcp dport 22 ip saddr @addr-set-sshd reject with icmp port-unreachable
	}
}

The banned address sees port 22 as filtered (see nmap); after unbanip it is open again.

Recipes

1

Management

bash
sudo fail2ban-client status               # all jails
sudo fail2ban-client status sshd          # who's banned, counters
sudo fail2ban-client set sshd unbanip 1.2.3.4   # unban
sudo fail2ban-client set sshd banip 1.2.3.4     # ban manually
sudo fail2ban-client get sshd bantime     # a parameter's current value
sudo fail2ban-client reload               # reload the config
sudo fail2ban-regex /var/log/auth.log sshd  # test a filter
sudo tail -f /var/log/fail2ban.log        # decisions: Found, Ban

Troubleshooting

5

I banned myself

From the console (hypervisor/serial) or from an allowed IP: fail2ban-client set sshd unbanip <your IP>. Add your network to ignoreip.

The jail isn't banning anyone

  • Is enabled = true? Does fail2ban-client status show the jail?
  • Is logpath correct and the filter matching your log format? On Ubuntu, SSH is often in journald — you need backend = systemd.
  • Test the filter: does fail2ban-regex on the real log catch the lines?

The address is not banned: Ignore by ip

The address is in ignoreip: failures from it are not counted, Total failed stays 0, and /var/log/fail2ban.log writes for every journal line:

text
fail2ban.filter [3147]: INFO    [sshd] Ignore 192.0.2.20 by ip

Without the address in ignoreip the same attempts give Found and a ban:

text
fail2ban.filter  [3147]: INFO    [sshd] Found 192.0.2.20
  - 2026-10-21 05:50:02
fail2ban.actions [3147]: NOTICE  [sshd] Ban 192.0.2.20

The administrator's network belongs in ignoreip, the attacker's address does not. After an edit, run sudo fail2ban-client reload.

It's banning, but the attack continues from other IPs

That's a distributed brute force. Enable recidive, tighten maxretry/findtime, consider a geo/ASN block at the firewall level (see whois for CIDR ranges).

Not sure whether it's working at all

fail2ban-client status sshd → Total/Currently failed and banned. The Found, Ban and Unban lines are in /var/log/fail2ban.log.

Terms

2
brute force (password guessing)
An attack that tries logins with one password after another until one fits. It leaves hundreds of "Failed password" lines in the sshd log. Defences are key login, faillock and an address ban by fail2ban. Also appears in: sshd
jail (fail2ban)
A fail2ban bundle: where to read the log (backend, logpath), which filter to match, how many failures to allow (maxretry within findtime) and how long to ban the address (bantime). fail2ban-client status <jail> shows its state. Also appears in: Firewall, nmap: which ports are visible from outside, PAM: login checks, password policy and lockout, whois

See also

  • sshd — The SSH server — remote access via keys, config and hardening.
  • firewall — Traffic filtering — simple ufw and low-level nftables.
  • journalctl — Reading the systemd journal (journald) — filters by service, time, priority.
Loading…