Fail2ban Nginx Jail: Block Abusive IPs (HTTP 404/401 floods and scanners)

fail2ban nginx jail - custom-f2b-featured.png

Fail2ban watches log files and adds firewall blocks when patterns repeat. For Nginx that usually means credential stuffing on protected paths,
aggressive 404 scanning, or bots hammering /wp-admin and /.env on sites that do not even run WordPress.

This guide assumes Nginx is already serving traffic — see rate limiting and security headers for the first layer — and that you have
Fail2ban installed or will install it here.

How Fail2ban Fits With Nginx

Nginx writes one line per request to the access log. Fail2ban filters turn those lines into regex matches; jails count matches per IP inside a time window and call the firewall to drop traffic.

architecturefail2ban-flow.txt
  nginx access.log --> fail2ban filter --> jail (maxretry/findtime) --> banaction --> firewall
Fail2ban pipeline
Log line to ban

Install Fail2ban and Enable the Service

Most distributions package Fail2ban. Enable it before editing jails so your changes survive reboot.

bashinstall
sudo apt install -y fail2ban   # or: sudo dnf install -y fail2ban
bashenable
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
Install fail2ban
systemd unit

Use a Local Jail Override

Never edit jail.conf directly — package updates overwrite it. Put overrides in /etc/fail2ban/jail.local or jail.d/*.conf.

ini/etc/fail2ban/jail.local (defaults)
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
banaction = ufw
NoteOn firewalld hosts use banaction = firewallcmd-ipset instead of ufw.
jail.local
Overrides survive updates

Enable the nginx-http-auth Jail

If you use HTTP basic auth anywhere, repeated 401 responses from one IP are a good ban signal.

inienable jail
[nginx-http-auth]
enabled = true
port    = http,https
logpath = /var/log/nginx/*error.log
bashreload
sudo fail2ban-client reload
sudo fail2ban-client status nginx-http-auth
401-based jail
nginx-http-auth

Catch Aggressive 404 Scanners

A custom filter on the access log bans IPs that request dozens of non-existent paths in a few minutes. Tune thresholds so real users with broken bookmarks are not banned.

ini/etc/fail2ban/filter.d/nginx-404.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST|HEAD) .* HTTP.*" 404
ignoreregex =
ini/etc/fail2ban/jail.d/nginx-404.local
[nginx-404]
enabled  = true
port     = http,https
filter   = nginx-404
logpath  = /var/log/nginx/access.log
maxretry = 30
findtime = 5m
bantime  = 24h
404 flood filter
Custom filter + jail

Test Filters Before You Ban Production Traffic

Use fail2ban-regex against a slice of your real log so you see what would have matched yesterday.

bashtest filter
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-404.conf | tail -20
WarningStart with a high maxretry and short bantime, watch for false positives, then tighten.
fail2ban-regex
Dry-run on logs

Confirm Bans and Unban When Needed

List jails, inspect banned IPs, and unban a mistaken block without restarting Nginx.

bashstatus
sudo fail2ban-client status nginx-404
sudo ufw status | grep DENY
bashunban one IP
sudo fail2ban-client set nginx-404 unbanip 203.0.113.50
Status and unban
fail2ban-client

Quick Reference

  • Overrides in jail.local / jail.d
  • nginx-http-auth for 401 abuse; custom filter for 404 scanners
  • Test with fail2ban-regex before aggressive bantime

Related tutorials

Diagrams are original illustrations by Gnome IT Solutions. Tutorial text © Gnome IT Solutions.