fail2ban in Practice
Introduction¶
fail2ban scans log files for patterns that indicate abuse (repeated failed SSH logins, web auth failures, spam attempts), and adds a temporary firewall block for the offending IP. It's a blunt but effective way to cut brute-force noise.
The pieces¶
- Jail — a monitored service: which log, which filter, how many failures in what window trigger a ban, for how long, and what ban action.
- Filter — a set of regexes (
failregex) that match a "this was a failed attempt" log line and capture the source IP as<HOST>. - Action — what to do on a ban (add a firewall rule, send an email, call a script).
Configure via jail.local¶
Never edit jail.conf (package-owned). Create /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd # read the journal, not files (modern default)
banaction = nftables-multiport # or firewalld, or iptables-multiport
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24 # YOUR admin ranges — do this first
[sshd]
enabled = true
[nginx-http-auth]
enabled = true
logpath = /var/log/nginx/error.log
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5
ignoreip— allowlist your own admin IPs before enabling anything, or you'll ban yourself during testing.backend = systemd— readsjournalddirectly; nologpathneeded for services that log there (sshd). File-based jails still needlogpath.recidive— bans IPs that keep coming back after their first ban expires, for much longer. Watches fail2ban's own log.- Incremental bans:
bantime.increment = true,bantime.factor = 2doubles the ban each repeat offence.
Writing a filter¶
/etc/fail2ban/filter.d/myapp.conf:
[Definition]
failregex = ^.*authentication failed for user .* from <HOST>.*$
^.*invalid API key from <HOST>.*$
ignoreregex =
datepattern = %%Y-%%m-%%dT%%H:%%M:%%S
<HOST> is the magic token that captures the IP (or hostname). %% escapes %
in the ini file.
Ban actions¶
nftables-multiport/nftables-allports— adds the IP to an nft set (fail2bantable). Best on nft-based systems.firewalld-multiport/ firewalld ipset — integrates with firewalld.iptables-multiport— legacy.- Match the action to your firewall so bans actually take effect and survive a firewall reload (nftables/firewalld sets persist better than raw iptables rules).
Verification and troubleshooting¶
fail2ban-client status # enabled jails
fail2ban-client status sshd # currently banned, total, log path
fail2ban-client set sshd unbanip 198.51.100.5
fail2ban-client set sshd banip 198.51.100.66 # manual ban (test the action)
# Test a filter against a log without banning
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
fail2ban-regex --print-all-matched systemd-journal[unit=nginx.service] filter.d/nginx-http-auth.conf
- Jail enabled but never bans — the filter's
failregexdoesn't match the actual log lines (log format changed, wrongdatepattern).fail2ban-regexshows matched/missed counts. Also checklogpathexists and fail2ban can read it, orbackend = systemdfor journald services. - Bans happen but the IP still connects — the ban action doesn't match your
firewall (added an iptables rule but you use nftables/firewalld), or a
higher-priority allow rule.
nft list set inet fail2ban .../firewall-cmd --list-allto see if the ban is really in the firewall. - You banned yourself — console access;
fail2ban-client unban --allorset <jail> unbanip <ip>, then add your range toignoreipand restart. fail2ban.servicefails to start — a syntax error injail.local/ a filter;fail2ban-client -ddumps the parsed config,journalctl -u fail2ban.- Too aggressive / legit users banned —
maxretrytoo low orfindtimetoo long for a service where users fat-finger passwords; raisemaxretry, shortenfindtime, or narrow thefailregexto genuine attacks. - IPv6 not banned — old fail2ban or an action without
allports/multiportIPv6 support; modern versions + nftables handle both. - Cloud / behind a proxy — the log shows the proxy's IP, not the client's.
Configure the app to log
X-Forwarded-Forand adjust the filter, or ban at the proxy layer instead.
Related tools and reading¶
- On-site: Port Checker, Regex Tester.
- Related posts: SSH server hardening, firewalld: zones and rich rules.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Linux & Sysadmin
resolv.conf and systemd-resolved
On modern distros /etc/resolv.conf points at a stub resolver managed by systemd-resolved. Editing it directly usually does nothing — here's the real model.
October 24, 2026Tuning Open File Limits on Linux
Four different limits control how many files a process can open. 'Too many open files' means you're hitting one specific one — here's how to find and raise it.
October 24, 2026ss and conntrack for Connection Debugging
ss shows you every socket and its send/receive queues; conntrack shows what the firewall is tracking. Together they explain most 'connection refused' and 'no buffer space' problems.
October 24, 2026