Fail2Ban Setup Guide for Ubuntu Server

Block malicious IPs with /24 subnet banning for Apache2 web server.

Fail2Ban is a log-driven intrusion-prevention daemon. It watches log files for patterns that indicate abuse — repeated failed logins, probes for PHP admin panels, spam bots hitting a search endpoint — and temporarily blocks the offending addresses in the host firewall. This guide configures it to ban whole /24 subnets for an Apache web server, then explains how the pieces work and where the approach has limits.

1. Install Fail2Ban

sudo apt update
sudo apt install fail2ban -y

2. Create Custom Subnet Ban Action

Create a custom action that bans entire /24 subnets (256 IPs) instead of individual IPs:

sudo vim /etc/fail2ban/action.d/iptables-subnet.conf

Add the following content:

[Definition]
actionban = iptables -I INPUT -s <ip>/24 -j DROP
actionunban = iptables -D INPUT -s <ip>/24 -j DROP

3. Create Filters

3.1 Block /search Requests

Create a filter to catch spam bots hitting search endpoints:

sudo vim /etc/fail2ban/filter.d/apache-search.conf

Add the following content:

[Definition]
failregex = ^<HOST> .* "(GET|POST) /search\?.*"
ignoreregex =

3.2 Block PHP Requests

Create a filter to catch any request containing "php" in the URL:

sudo vim /etc/fail2ban/filter.d/apache-php.conf

Add the following content:

[Definition]
failregex = ^<HOST> .* "(GET|POST) .*php.*"
ignoreregex =

This filter will catch:

4. Configure Jails

Create the jail configuration file:

sudo vim /etc/fail2ban/jail.local

Add the following content:

[apache-search]
enabled = true
port = http,https
filter = apache-search
logpath = /var/log/apache2/protonchat.access.log
backend = auto
maxretry = 1
findtime = 86400
bantime = 432000
banaction = iptables-subnet

[apache-php]
enabled = true
port = http,https
filter = apache-php
logpath = /var/log/apache2/protonchat.access.log
backend = auto
maxretry = 1
findtime = 86400
bantime = 432000
banaction = iptables-subnet

Configuration Parameters Explained

5. Start Fail2Ban

sudo systemctl enable fail2ban
sudo systemctl restart fail2ban

6. Verify Configuration

6.1 Check Jail Status

# List all jails
sudo fail2ban-client status

# Check specific jail
sudo fail2ban-client status apache-search
sudo fail2ban-client status apache-php

6.2 Test Regex Against Log File

sudo fail2ban-regex /var/log/apache2/protonchat.access.log /etc/fail2ban/filter.d/apache-search.conf
sudo fail2ban-regex /var/log/apache2/protonchat.access.log /etc/fail2ban/filter.d/apache-php.conf

6.3 Verify IPTables Rules

sudo iptables -L INPUT -n | grep "/24"

Expected output:

DROP       0    --  103.3.220.0/24       0.0.0.0/0           
DROP       0    --  102.89.75.0/24       0.0.0.0/0           
DROP       0    --  125.164.122.0/24     0.0.0.0/0

7. Useful Management Commands

7.1 View Banned IPs

# View all banned IPs for a jail
sudo fail2ban-client get apache-search banned

# View jail status with ban list
sudo fail2ban-client status apache-search

7.2 Unban IPs

# Unban a specific IP
sudo fail2ban-client set apache-search unbanip 1.2.3.4

# Unban all IPs from all jails
sudo fail2ban-client unban --all

7.3 Monitor Logs

# Watch fail2ban activity in real-time
sudo tail -f /var/log/fail2ban.log

8. File Locations Summary

  1. Main config: /etc/fail2ban/jail.conf (do not edit)
  2. Custom jails: /etc/fail2ban/jail.local
  3. Filters: /etc/fail2ban/filter.d/
  4. Actions: /etc/fail2ban/action.d/
  5. Fail2ban log: /var/log/fail2ban.log

9. How it works

How Fail2Ban Works Apache log access.log Filter failregex Jail maxretry, findtime Action iptables-subnet iptables DROP /24 The fail2ban-server daemon tails each jail's log, counts regex matches per host, and runs the ban action.

Fail2Ban runs as a server process (fail2ban-server) controlled by fail2ban-client. Each jail ties together one or more log paths, a filter and an action. The filter is a set of Python regular expressions in which the placeholder <HOST> captures the client address. When a log line matches failregex and not ignoreregex, the jail records a failure for that host with the line's timestamp. If the host accumulates maxretry failures inside a sliding window of findtime seconds, the jail calls the action's actionban command with the address substituted for <ip>. After bantime seconds it calls actionunban.

The custom action in step 2 turns the single address into a /24 by appending the prefix length. iptables accepts host bits in the source and masks them, so 203.0.113.57/24 becomes a rule for 203.0.113.0/24. Inserting with -I places the rule at the top of INPUT so it takes effect before any accept rules.

10. Ban lifecycle

Ban Lifecycle for One Offender Request matches regex Count 1 within 24 h Ban rule inserted 5 days bantime Unban rule deleted With maxretry = 1 the first match bans; raise it for login jails to tolerate typos. Bans live in memory and the fail2ban database; a restart re-applies active bans.

The configuration above uses a 24-hour window and a five-day ban with a single strike. That is aggressive and suits requests no legitimate visitor makes, such as PHP paths on a site that serves no PHP. For SSH or login forms, a more forgiving setting such as maxretry = 5, findtime = 600 avoids locking out users who mistype a password. Fail2Ban also offers a recidive jail that watches its own log and applies long bans to addresses that are banned repeatedly.

11. Trade-offs

ChoiceBenefitCost
Ban /24 instead of single IPStops bots rotating through neighbouring addressesCan block innocent users behind the same ISP or cloud range
maxretry = 1Immediate response to obvious probesNo tolerance for a mistaken URL
Long bantimeFewer repeat hits in logsLarger iptables chain, slower to recover from a false positive
Log-based detectionWorks with any service that logsReacts after the request has been served

Fail2Ban complements, rather than replaces, a default-deny firewall, application authentication and rate limiting. It is reactive by design: the first offending request is always served. For high-volume attacks, ipset-based actions (such as the bundled iptables-ipset or nftables actions) scale better than one iptables rule per ban because lookups are hashed rather than linear.

12. Pitfalls

To remove Fail2Ban and its rules cleanly, see the Fail2Ban uninstall guide. For cloud-level filtering in front of a server, see AWS Network Security.