# fail2ban for Apache

> Set up fail2ban for Apache httpd/apache2: every stock apache jail explained, Debian vs RHEL log paths, the LogLevel some filters need, and a custom 404 filter.
>
> Source: https://fail2ban.dev/guides/apache/ · Updated 2026-10-25 · Checked against fail2ban 1.1.1
> fail2ban.dev is an independent guide, not the official fail2ban project.

To protect Apache with fail2ban, enable the stock Apache jails in `/etc/fail2ban/jail.local` — at minimum `apache-auth`, `apache-badbots`, `apache-noscript` and `apache-overflows` — with `backend = auto`, then run `sudo fail2ban-client reload`. fail2ban reads `/var/log/apache2/*error.log` on Debian and Ubuntu and `/var/log/httpd/*error_log` on Fedora and RHEL automatically. For 404 scanners, add the custom filter at the end of this page.

```ini
[apache-auth]
enabled = true
backend = auto

[apache-badbots]
enabled = true
backend = auto

[apache-noscript]
enabled = true
backend = auto

[apache-overflows]
enabled = true
backend = auto

[apache-shellshock]
enabled = true
backend = auto
```
sudo fail2ban-client reload
sudo fail2ban-client status
```

## Apache log paths: apache2 vs httpd

The jails don't hard-code paths. They use variables from the distribution's `paths-*.conf`:

| Variable | Debian / Ubuntu (`apache2`) | Fedora / RHEL / Rocky / Alma (`httpd`) |
|---|---|---|
| `apache_error_log` | `/var/log/apache2/*error.log` | `/var/log/httpd/*error_log` |
| `apache_access_log` | `/var/log/apache2/*access.log` | `/var/log/httpd/*access_log` |

The globs pick up per-site logs such as `example.com-error.log` — but only files that exist when the jail starts. If a vhost logs somewhere else, add it:

```ini
[apache-auth]
enabled = true
backend = auto
logpath = %(apache_error_log)s
          /srv/www/example.com/logs/error.log
```

## Every stock Apache jail

| Jail | Log | jail.conf defaults | Catches |
|---|---|---|---|
| [`apache-auth`](/guides/apache/#filter-apache-auth) | error | maxretry 5 | Basic/Digest auth failures, unknown users, "denied by server configuration" |
| [`apache-badbots`](/guides/apache/#filter-apache-badbots) | access | `maxretry = 1`, `bantime = 48h` | User agents of known spam/e-mail harvesting bots |
| [`apache-noscript`](/guides/apache/#filter-apache-noscript) | error | maxretry 5 | Requests for scripts that don't exist (`.php`, `.asp`, `.exe`, `.pl`, cgi-bin), incl. PHP-FPM "Primary script unknown" |
| [`apache-overflows`](/guides/apache/#filter-apache-overflows) | error | `maxretry = 2` | Overlong URIs, invalid methods and URIs, bad characters |
| `apache-nohome` | error | `maxretry = 2` | Probes for `~user` home directories |
| [`apache-botsearch`](/guides/apache/#filter-apache-botsearch) | error | `maxretry = 2` | Probes for phpMyAdmin, webmail, `wp-login.php`, cgi-bin that don't exist |
| [`apache-fakegooglebot`](/guides/apache/#filter-apache-fakegooglebot) | access | `maxretry = 1` | Clients claiming to be Googlebot whose IP doesn't resolve to Google |
| `apache-modsecurity` | error | `maxretry = 2` | Requests ModSecurity denied with a 4xx/5xx code |
| `apache-shellshock` | error | `maxretry = 1` | Shellshock (CVE-2014-6271) header attacks against CGI |

All of them use `port = http,https`.

### apache-auth

Catches Apache 2.4 authentication errors such as:

```log
[Sun Oct 25 18:36:12.654321 2026] [auth_basic:error] [pid 2345] [client 203.0.113.42:51234] AH01617: user admin: authentication failure for "/private/": Password Mismatch
```

### apache-noscript and apache-overflows

Bots constantly request `/wp-login.php`, `/xmlrpc.php` or `/shell.php` on sites that have none of them. With PHP-FPM, Apache logs these as:

```log
```

### apache-botsearch and apache-nohome need LogLevel info

Both filters match `AH00128: File does not exist`, which Apache 2.4 logs at **info** level. With the default `LogLevel warn` these lines never appear and the jails stay at zero. Raise the level for the core module only:

```apache
LogLevel warn core:info
```

```ini
[apache-botsearch]
enabled = true
backend = auto
filter  = apache-botsearch[webroot="/var/www/html/"]
```

### apache-fakegooglebot

This jail matches every access-log line whose user agent contains `Googlebot`, then runs an `ignorecommand` script that does a reverse and forward DNS check. Real Googlebot addresses are ignored; impostors get banned on the first request. It costs one DNS lookup per Googlebot request, so enable it only if fake crawlers are a real problem for you.

### apache-modsecurity and apache-shellshock

`apache-modsecurity` turns ModSecurity's per-request denials into firewall bans: after two blocked requests the client can't reach the server at all. It only makes sense if mod_security2 is installed with a rule set such as the OWASP CRS. `apache-shellshock` bans clients sending Shellshock payloads to CGI scripts; on a patched server it mostly cleans up noise.

## Ban Apache 404 floods with a custom filter

There's no stock 404 filter. This one reads the `combined` access-log format (and Debian's `vhost_combined` used for `other_vhosts_access.log`), with the status codes chosen per jail:

```ini
[Definition]
failregex = ^(?:\S+:\d+ )?<HOST> \S+ \S+ \[\] "[A-Z]+ [^"]*" (?:<codes>)\s
ignoreregex = "(?:GET|HEAD) /(?:favicon\.ico|robots\.txt|apple-touch-icon\S*\.png)\s
datepattern = ^[^\[]*\[({DATE})
              {^LN-BEG}

[Init]
codes = 404
```
[apache-404]
enabled  = true
backend  = auto
filter   = apache-4xx
logpath  = %(apache_access_log)s
port     = http,https
findtime = 10m
maxretry = 20
bantime  = 1h

[apache-403]
enabled  = true
backend  = auto
filter   = apache-4xx[codes="401|403"]
logpath  = %(apache_access_log)s
port     = http,https
maxretry = 10
```

```log
example.com:443 203.0.113.42 - - [25/Oct/2026:18:36:10 +0000] "GET /.git/config HTTP/1.1" 404 196 "-" "curl/8.5.0"
```

## Apache behind a proxy or CDN

Behind a load balancer, reverse proxy or Cloudflare, Apache logs the proxy's address and fail2ban would ban the proxy. Use `mod_remoteip` so Apache logs the client:

```apache
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 10.0.0.5
```
sudo a2enmod remoteip && sudo a2enconf remoteip && sudo systemctl reload apache2
```

## Test the Apache jails

```bash
sudo fail2ban-regex /var/log/apache2/error.log apache-auth
sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/apache-4xx.conf

# RHEL/Fedora
sudo fail2ban-regex /var/log/httpd/error_log apache-noscript
```

```bash
sudo fail2ban-client get apache-404 logpath
```

## Built-in filter reference: apache-auth, apache-badbots, apache-botsearch and more

{{component:filter-ref:apache-auth.apache-badbots.apache-botsearch.apache-fakegooglebot.apache-modsecurity.apache-nohome.apache-noscript.apache-overflows.apache-shellshock.apache-pass}}

## FAQ

### Which Apache filters does fail2ban include?

fail2ban 1.1.1 ships `apache-auth`, `apache-badbots`, `apache-botsearch`, `apache-fakegooglebot`, `apache-modsecurity`, `apache-nohome`, `apache-noscript`, `apache-overflows` and `apache-shellshock`, each with a disabled jail of the same name in `jail.conf`. There's also `apache-pass`, used by the `pass2allow-ftp` port-knocking example jail.

### How do I ban Apache 404 errors with fail2ban?

Create a filter matching status 404 in the access log, such as `failregex = ^<HOST> \S+ \S+ \[\] "[A-Z]+ [^"]*" 404\s`, and a jail with `logpath = %(apache_access_log)s`, `maxretry = 20` and `findtime = 10m`. Ignore `favicon.ico` and `robots.txt` so ordinary browsers aren't counted.

### Why is apache-botsearch not banning anything?

Apache 2.4 logs `File does not exist` at info level, so with `LogLevel warn` the lines never reach the error log. Set `LogLevel warn core:info`. Also pass your real document root, e.g. `filter = apache-botsearch[webroot="/var/www/html/"]`, because the filter defaults to `/var/www/`.

### Does fail2ban work with httpd on RHEL and Rocky Linux?

Yes. The Fedora/EPEL package uses `paths-fedora.conf`, which points the Apache jails at `/var/log/httpd/*error_log` and `*access_log`. Enable the jails in `jail.local` as on Debian; with fail2ban-firewalld installed, bans are applied through firewalld.

### Where are the Apache logs fail2ban reads?

On Debian and Ubuntu: `/var/log/apache2/*error.log` and `/var/log/apache2/*access.log`. On Fedora, RHEL, Rocky and AlmaLinux: `/var/log/httpd/*error_log` and `/var/log/httpd/*access_log`. Vhosts logging elsewhere need extra `logpath` lines in the jail.
