When implementing Fail2Ban with Nginx, we often need granular control over blocking behaviors based on different HTTP status codes. The standard configuration treats all failed requests equally, but in reality:
- 404 (Not Found) errors might indicate scanning attempts
- 403 (Forbidden) errors often suggest actual attack patterns
- Different thresholds should apply based on threat severity
We'll create separate Fail2Ban filters and jails for each status code pattern:
# /etc/fail2ban/filter.d/nginx-404.conf
[Definition]
failregex = ^.*"GET.*HTTP/.*" 404 .*$
ignoreregex =
# /etc/fail2ban/filter.d/nginx-403.conf
[Definition]
failregex = ^.*"GET.*HTTP/.*" 403 .*$
ignoreregex =
Now configure separate jails in /etc/fail2ban/jail.local
:
[nginx-404]
enabled = true
filter = nginx-404
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 300
bantime = 86400
[nginx-403]
enabled = true
filter = nginx-403
logpath = /var/log/nginx/error.log
maxretry = 3
findtime = 300
bantime = 86400
For more sophisticated detection, combine multiple conditions:
# Detect repeated 404s to specific sensitive paths
failregex = ^.*"(GET|POST).*(wp-admin|config|\.env).*HTTP/.*" 404 .*$
# Detect 403s with specific attack patterns
failregex = ^.*"(GET|POST).*(\.php|\.asp|cmd\.exe).*HTTP/.*" 403 .*$
Always test new filters before deployment:
fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-404.conf
fail2ban-client status nginx-404
fail2ban-client set nginx-404 unbanip 1.2.3.4
When implementing multiple jails:
- Monitor system resources with
fail2ban-client status
- Consider log file rotation impact
- Adjust
findtime
based on your traffic volume
When using Fail2Ban with Nginx, the default configurations typically trigger IP blocking based on generic failed login attempts or brute-force patterns. However, web applications often need more granular control - particularly when dealing with different HTTP status codes. A 404 (Not Found) might indicate scanning attempts, while 403 (Forbidden) could signal unauthorized access attempts.
We'll create separate Fail2Ban filters and jails for each status code pattern:
# /etc/fail2ban/filter.d/nginx-404.conf
[Definition]
failregex = ^ .* "(GET|POST|HEAD).*HTTP.*" 404 .*$
ignoreregex =
# /etc/fail2ban/filter.d/nginx-403.conf
[Definition]
failregex = ^ .* "(GET|POST|HEAD).*HTTP.*" 403 .*$
ignoreregex =
In your jail.local (or jail.d/nginx.conf):
[nginx-404]
enabled = true
port = http,https
filter = nginx-404
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 300
bantime = 86400
[nginx-403]
enabled = true
port = http,https
filter = nginx-403
logpath = /var/log/nginx/error.log
maxretry = 3
findtime = 300
bantime = 86400
Always verify your regex patterns before applying:
fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-404.conf
For more complex scenarios, you can combine multiple conditions:
# Block IPs hitting specific URLs with 404s
failregex = ^ .* "(GET|POST).*/wp-admin.*HTTP.*" 404
When monitoring multiple status codes:
- Use separate log files for different virtual hosts
- Consider log rotation settings
- Monitor Fail2Ban's memory usage
Remember to restart Fail2Ban after configuration changes:
systemctl restart fail2ban