Operations 8 min read

Three Production‑Ready Dynamic IP Blocking Solutions for Nginx (No Manual Reload)

This guide presents three practical, production‑grade methods to dynamically block IP addresses in Nginx—using OpenResty with Redis for millisecond response, fail2ban with log analysis for automated bans, and a pure‑shell file‑watch approach—each with step‑by‑step installation, configuration, and usage instructions.

Xiao Liu Lab
Xiao Liu Lab
Xiao Liu Lab
Three Production‑Ready Dynamic IP Blocking Solutions for Nginx (No Manual Reload)

Solution 1: OpenResty + Redis (millisecond‑level dynamic blocking)

Install OpenResty and Redis, then configure Nginx to query Redis for a blacklist and deny matching IPs without reloading.

Install OpenResty and Redis on Ubuntu:

# Ubuntu example
sudo apt install redis-server -y
wget -O - https://openresty.org/package/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/openresty-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/openresty-archive-keyring.gpg] http://openresty.org/package/debian $(lsb_release -sc) openresty" | sudo tee /etc/apt/sources.list.d/openresty.list
sudo apt update && sudo apt install -y openresty

Configure /etc/openresty/nginx.conf to load the Redis library and deny blacklisted IPs:

worker_processes auto;
events { worker_connections 1024; }
http {
    server {
        listen 80;
        location / {
            access_by_lua_block {
                local redis = require "resty.redis"
                local red = redis:new()
                red:set_timeout(1000)
                local ok, err = red:connect("127.0.0.1", 6379)
                if not ok then return end
                local ip = ngx.var.remote_addr
                if red:get("blacklist:" .. ip) ~= ngx.null then
                    ngx.exit(403)
                end
                red:close()
            }
            proxy_pass http://127.0.0.1:8080;
        }
    }
}

Block or unblock an IP with a single Redis command:

# Block for 1 hour
redis-cli SETEX blacklist:1.2.3.4 3600 "abuse"
# Unblock
redis-cli DEL blacklist:1.2.3.4

Solution 2: fail2ban + Nginx logs (automatic analysis)

Use fail2ban to parse Nginx access logs and automatically ban offending IPs via iptables.

Install fail2ban: sudo apt install fail2ban -y Create a filter /etc/fail2ban/filter.d/nginx-bad.conf :

[Definition]
failregex = ^<HOST>.*"(GET|POST).*" (400|403|444|404) .*
ignoreregex =

Configure a jail /etc/fail2ban/jail.local :

[nginx-bad]
enabled = true
port = http,https
filter = nginx-bad
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 3600
action = iptables-multiport[name=nginx, port="80,443"]

Restart fail2ban to apply the rules:

sudo systemctl restart fail2ban

Solution 3: Pure Shell + File Watch (zero dependencies)

Maintain a plain‑text blacklist file and use a shell script together with inotifywait to regenerate Nginx deny directives automatically.

Install inotify-tools : sudo apt install inotify-tools -y Create the blacklist directory and initial files:

sudo mkdir -p /etc/nginx/dynamic
echo "# Blacklist IP, one per line" | sudo tee /etc/nginx/blacklist.txt
sudo touch /etc/nginx/dynamic/blacklist.conf

Write the conversion script /usr/local/bin/gen_nginx_blacklist.sh :

#!/bin/bash
INPUT="/etc/nginx/blacklist.txt"
OUTPUT="/etc/nginx/dynamic/blacklist.conf"
# Header
echo "# Auto‑generated from blacklist.txt. DO NOT EDIT." > "$OUTPUT"
# Generate deny rules
while IFS= read -r line; do
    line=$(echo "$line" | xargs)   # trim spaces
    if [[ -n "$line" && "$line" != \#* ]]; then
        echo "deny $line;" >> "$OUTPUT"
    fi
done < "$INPUT"
# Test and reload Nginx
nginx -t && systemctl reload nginx

Make it executable:

sudo chmod +x /usr/local/bin/gen_nginx_blacklist.sh

Include the generated file in the Nginx server block:

server {
    listen 80;
    include /etc/nginx/dynamic/blacklist.conf;  # key line
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

Start a background watcher that regenerates the file on changes (or create a systemd service):

nohup inotifywait -m -e modify,move,create,delete /etc/nginx/blacklist.txt \
  --format '%f' |
  while read file; do
    echo "[$(date)] blacklist.txt changed, regenerating..."
    /usr/local/bin/gen_nginx_blacklist.sh
  done &

Choosing a solution

High‑concurrency API gateway or any service that needs millisecond response: Solution 1 (OpenResty + Redis)

Brute‑force protection for WordPress or small sites: Solution 2 (fail2ban)

Prefer no extra packages, pure Nginx file‑based workflow: Solution 3 (Shell + file watch)

OpenRestyshell scriptIP blockingFail2Ban
Xiao Liu Lab
Written by

Xiao Liu Lab

An operations lab passionate about server tinkering 🔬 Sharing automation scripts, high-availability architecture, alert optimization, and incident reviews. Using technology to reduce overtime and experience to avoid major pitfalls. Follow me for easier, more reliable operations!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.