Skip to main content
Blog|
Learning center

What Is fail2ban and How Does It Work

|
Mar 20, 2026|10 min read
LEARNING CENTERWhat Is fail2ban and How DoesIt WorkHOSTNEYhostney.comMarch 20, 2026

fail2ban monitors log files for patterns that indicate malicious activity – failed SSH login attempts, repeated 404s from a single IP, brute force attacks against a WordPress login page – and automatically bans the offending IP addresses by adding firewall rules. It is one of the most widely deployed security tools on Linux servers.

The core concept is simple: if an IP address fails authentication 5 times in 10 minutes, block it for 30 minutes. The thresholds, time windows, and ban durations are all configurable. fail2ban watches the logs, counts the failures, and manages the bans. You define the rules.

How fail2ban works#

fail2ban runs as a background service (daemon) and follows a straightforward loop:

  1. It reads log files line by line in real time (similar to  tail -f )
  2. Each new line is matched against patterns called “filters” – regular expressions that identify failures
  3. When a filter matches, fail2ban records the source IP address and increments a counter
  4. When the counter for an IP reaches the configured threshold (maxretry) within the configured time window (findtime), fail2ban triggers a “ban action”
  5. The ban action adds a firewall rule (typically an iptables rule) that drops all packets from the banned IP
  6. After the ban duration (bantime) expires, fail2ban removes the firewall rule and the IP can connect again

The entire process is reactive. fail2ban does not inspect live network traffic. It reads log files after the fact. The attacker’s requests reach your server, generate log entries, and only then does fail2ban notice and respond. This means the first few attempts always get through – the ban only kicks in after the threshold is exceeded.

The components

fail2ban has three main concepts:

Filters define what to look for in log files. A filter is a set of regular expressions that match specific log patterns. For example, the SSH filter matches lines like:

Failed password for invalid user admin from 198.51.100.20 port 45678 ssh2

Jails combine a filter with a log file, thresholds, and an action. A jail says: “Watch this log file with this filter. If an IP matches more than X times in Y seconds, execute this action for Z seconds.”

Actions define what happens when a ban is triggered. The most common action is adding an iptables rule to drop traffic from the IP. Other actions can send email notifications, run custom scripts, or update external blocklists.

Installing fail2ban#

On Ubuntu/Debian

sudo apt update
sudo apt install fail2ban

On CentOS/RHEL

sudo dnf install epel-release
sudo dnf install fail2ban

Start and enable the service

sudo systemctl start fail2ban
sudo systemctl enable fail2ban

The enable command ensures fail2ban starts automatically on boot.

Verify it is running

sudo systemctl status fail2ban

You should see active (running) .

Configuration#

fail2ban’s configuration is split across several files:

  • /etc/fail2ban/jail.conf  – the default configuration (do not edit this file)
  • /etc/fail2ban/jail.local  – your overrides (create this file)
  • /etc/fail2ban/jail.d/  – directory for additional jail configurations
  • /etc/fail2ban/filter.d/  – filter definitions

The jail.conf file is overwritten on package updates. Always put your customizations in jail.local or in files under jail.d/ . Settings in jail.local override jail.conf .

Create jail.local

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Or create a minimal file with just your overrides:

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5

Default settings

SettingDefaultMeaning
bantime 10mHow long an IP is banned
findtime 10mThe time window for counting failures
maxretry 5Number of failures before banning
ignoreip 127.0.0.1/8IPs that are never banned

These defaults mean: if an IP fails 5 times within 10 minutes, ban it for 10 minutes. For most production servers, the defaults are too lenient. A 10-minute ban barely slows down an attacker running automated tools.

Recommended production settings

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 YOUR_IP_HERE

banaction = iptables-multiport

Replace YOUR_IP_HERE with your own IP address or office IP range so you do not accidentally lock yourself out. Use CIDR notation for ranges: 192.168.1.0/24 .

Incremental ban times

fail2ban supports increasing ban durations for repeat offenders:

[DEFAULT]
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w

With these settings, the first ban is 1 hour, the second is 2 hours, the third is 4 hours, and so on, up to a maximum of 1 week. This is effective against persistent attackers who return after each ban expires.

Common jails#

SSH jail

The SSH jail is enabled by default on most installations. It watches the SSH authentication log for failed login attempts.

[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 3
bantime = 1h

On CentOS/RHEL, the log path is /var/log/secure instead of /var/log/auth.log .

This is the most important jail on any server with SSH access. Automated bots constantly scan the internet for SSH servers and attempt credential stuffing with common username/password combinations. Without fail2ban, a public-facing SSH server accumulates thousands of failed login attempts per day. See SSH Connection Refused: What It Means and How to Fix It for how IP bans interact with SSH connection errors.

WordPress login jail

WordPress login brute force attacks hit /wp-login.php and /xmlrpc.php . fail2ban can monitor the web server access log for these patterns.

Create a filter file:

sudo nano /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php
            ^<HOST> .* "POST /xmlrpc\.php
ignoreregex =

Create the jail in /etc/fail2ban/jail.local :

[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 5m
bantime = 1h

This bans any IP that sends more than 5 POST requests to wp-login.php or xmlrpc.php within 5 minutes. For a deeper look at what bot traffic against WordPress login pages looks like and the damage it causes, see What happens when bots find your WordPress login page.

Nginx HTTP authentication jail

If you use Nginx’s built-in HTTP basic authentication:

[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 1h

This jail uses the built-in nginx-http-auth filter that ships with fail2ban.

Nginx bad bot jail

Block IPs that generate excessive 404 errors (typically scanners probing for vulnerable files):

Create /etc/fail2ban/filter.d/nginx-404.conf :

[Definition]
failregex = ^<HOST> .* "(GET|POST) .* HTTP/.*" 404
ignoreregex = \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)

The ignoreregex excludes 404s for static assets, which are usually legitimate missing files rather than scanning activity.

[nginx-404]
enabled = true
port = http,https
filter = nginx-404
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 1m
bantime = 30m

A threshold of 20 in 1 minute catches aggressive scanners without banning legitimate visitors who hit a few broken links.

Nginx rate limiting jail

If you use Nginx’s limit_req module, failed requests are logged to the error log. fail2ban can watch for the excess:

[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 1h

Managing bans#

Check banned IPs

sudo fail2ban-client status sshd

Output:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 2
|  |- Total failed: 847
|  `- File list: /var/log/auth.log
`- Actions
   |- Currently banned: 3
   |- Total banned: 156
   `- Banned IP list: 198.51.100.20 203.0.113.45 192.0.2.100

This shows the current state of the SSH jail: how many IPs are currently banned, total historical bans, and the specific IPs that are currently blocked.

List all active jails

sudo fail2ban-client status

Shows all enabled jails and their ban counts.

Unban a specific IP

sudo fail2ban-client set sshd unbanip 198.51.100.20

Replace sshd with the jail name and the IP with the address to unban. This is the command you need when a legitimate user gets locked out. It takes effect immediately.

Unban from all jails at once

sudo fail2ban-client unban 198.51.100.20

Without specifying a jail, this removes the IP from every jail.

Manually ban an IP

sudo fail2ban-client set sshd banip 198.51.100.20

Adds a ban manually without waiting for log matches.

Check if a specific IP is banned

sudo fail2ban-client get sshd banned 198.51.100.20

Returns 1 if banned, 0 if not.

How fail2ban interacts with the firewall#

fail2ban manages firewall rules through its “ban action.” The default action on most Linux systems uses iptables.

When fail2ban bans an IP, it runs a command like:

iptables -I f2b-sshd -s 198.51.100.20 -j REJECT

This inserts a rule in the f2b-sshd chain that rejects all traffic from that IP. When the ban expires, fail2ban removes the rule.

You can see the fail2ban rules in your firewall:

sudo iptables -L f2b-sshd -n

fail2ban with nftables

On newer systems using nftables instead of iptables, configure the ban action accordingly:

[DEFAULT]
banaction = nftables-multiport

fail2ban with firewalld

On CentOS/RHEL systems using firewalld:

[DEFAULT]
banaction = firewallcmd-rich-rules

Logging and monitoring#

fail2ban’s own log

fail2ban logs its actions to /var/log/fail2ban.log :

tail -50 /var/log/fail2ban.log

Each ban and unban is logged with the jail name, IP address, and timestamp. This log is useful for understanding ban patterns and identifying persistent attackers.

Email notifications

fail2ban can send email notifications on bans:

[DEFAULT]
destemail = admin@yourdomain.com
sender = fail2ban@yourdomain.com
mta = sendmail
action = %(action_mwl)s

The action_mwl sends an email with the ban details including whois information and relevant log lines. This is useful on low-traffic servers but generates too much mail on servers under heavy attack.

Troubleshooting#

fail2ban is not banning IPs

Check that the jail is enabled:

sudo fail2ban-client status

If the jail is not listed, it is not enabled. Add enabled = true to the jail configuration.

Check that the log file exists and is being written to:

ls -la /var/log/auth.log
tail -5 /var/log/auth.log

If the log file does not exist or is empty, fail2ban has nothing to watch.

Check the filter matches the log format:

sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

This tests the filter regex against the actual log file and reports how many lines match. If the match count is zero, the filter pattern does not match your log format.

fail2ban banned my own IP

This happens when you mistype your password multiple times or when automated tools (backup scripts, monitoring agents) use the wrong credentials.

Unban yourself:

sudo fail2ban-client set sshd unbanip YOUR_IP

Then add your IP to the ignore list to prevent it from happening again:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_IP_HERE

Restart fail2ban after changing the configuration:

sudo systemctl restart fail2ban

fail2ban is not starting

Check the logs for errors:

sudo journalctl -u fail2ban --no-pager -n 50

Common causes:

  • Syntax error in jail.local (missing brackets, wrong indentation)
  • A jail references a log file that does not exist
  • A filter file has an invalid regular expression

Bans are not persisting after restart

By default, fail2ban loses all active bans when the service restarts. To persist bans across restarts, enable the database:

[DEFAULT]
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 1d

The dbpurgeage setting controls how long ban history is kept.

fail2ban vs server-level bot detection#

fail2ban is a reactive tool. It reads logs, counts failures, and bans after the threshold is exceeded. This means:

  • The attacker’s first several requests always reach your server
  • Each request consumes server resources (PHP-FPM workers, database queries, CPU)
  • The ban only takes effect after the damage has started
  • Sophisticated attackers rotate IP addresses, staying under the threshold on each one

Server-level bot detection systems work differently. Hostney’s bot detection system scores incoming requests based on behavioral signals before they reach your application: request patterns, TLS fingerprinting, header analysis, and cross-site reputation data. A bot that has been attacking other sites on the platform is already flagged before it sends its first request to your server.

The difference is where and when the decision is made:

fail2banServer-level bot detection
When it actsAfter failures are loggedBefore the request reaches PHP
What it seesIndividual log entriesFull request context and cross-site behavior
IP rotationEach new IP starts freshBehavioral patterns carry across IPs
Resource costAttacker’s requests consume PHP workers until bannedBlocked at the edge before consuming application resources
ConfigurationManual per-serverAutomatic, platform-wide

Both have a role. On a self-managed VPS where you control the entire stack, fail2ban is essential. It is the standard tool for SSH protection, and its WordPress and Nginx jails catch the most obvious attacks. On a managed platform with built-in bot detection, fail2ban’s role is reduced because the platform handles the heavy lifting at a layer fail2ban cannot reach.

For a comparison of application-level security plugins versus server-level protection, see Wordfence and server-level security: why you need both.

fail2ban on Hostney#

On Hostney, each account runs in an isolated container with server-level bot detection active by default. fail2ban is not available or needed on Hostney’s managed hosting platform because:

  • SSH brute force protection is handled at the platform level
  • WordPress login attacks are blocked by the bot detection system before they reach PHP
  • IP-based rate limiting is enforced at the edge

fail2ban is a tool for servers you manage yourself. If you run a VPS or dedicated server and administer it directly, fail2ban is one of the first things to install. On managed hosting where the provider handles security at the infrastructure level, it is not applicable.