How to Build a Dynamic IP Blacklist with Nginx, Lua, and Redis

This guide explains how to create a dynamic IP blacklist that blocks malicious crawlers or users by rejecting requests from listed IPs, supports configurable expiration, and is implemented using Nginx (OpenResty), Lua scripts, and Redis for shared, lightweight, and scalable protection.

Architecture Digest
Architecture Digest
Architecture Digest
How to Build a Dynamic IP Blacklist with Nginx, Lua, and Redis

To block malicious crawlers or users, a dynamic IP blacklist is required that rejects requests from listed IPs and allows setting an expiration time.

Environment Preparation

Linux (CentOS7 / Ubuntu)

Redis 5.0.5

Nginx (OpenResty)

Design Options

OS level (iptables) – simple and direct but manual and inflexible.

Nginx deny or Lua plugin – can be dynamic and support distributed bans, but requires Lua knowledge.

Application‑layer check – easy to maintain via code, yet may add overhead under high concurrency.

For a lightweight, shared, and dynamic solution we choose the Nginx + Lua + Redis architecture.

Configure nginx.conf

Add the following to the location block that needs protection:

location / {
    # access_by_lua_file loads the Lua script that implements rate limiting
    access_by_lua_file /usr/local/lua/access_limit.lua;
    alias /usr/web/;
    index index.html index.htm;
}

Lua Script ( access_limit.lua )

-- This script implements automatic blacklisting of IPs that exceed request limits
local pool_max_idle_time = 10000
local pool_size = 100
local redis_connection_timeout = 100
local redis_host = "your redis host ip"
local redis_port = "your redis port"
local redis_auth = "your redis authpassword"
local ip_block_time = 120          -- block duration (seconds)
local ip_time_out = 1               -- counting window (seconds)
local ip_max_count = 3              -- max requests in window

local function errlog(msg, ex)
    ngx.log(ngx.ERR, msg, ex)
end

local function close_redis(red)
    if not red then return end
    local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx.say("redis connct err:", err)
        return red:close()
    end
end

local redis = require "resty.redis"
local client = redis:new()
local ok, err = client:connect(redis_host, redis_port)
if not ok then
    close_redis(client)
    ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
client:set_timeout(redis_connection_timeout)
local connCount, err = client:get_reused_times()
if connCount == 0 then
    local ok, err = client:auth(redis_auth)
    if not ok then errlog("failed to auth: ", err) return end
end

local function getIp()
    local clientIP = ngx.req.get_headers()["X-Real-IP"]
    if not clientIP then clientIP = ngx.req.get_headers()["x_forwarded_for"] end
    if not clientIP then clientIP = ngx.var.remote_addr end
    return clientIP
end

local cliendIp = getIp()
local incrKey = "limit:count:" .. cliendIp
local blockKey = "limit:block:" .. cliendIp

local is_block, err = client:get(blockKey)
if tonumber(is_block) == 1 then
    ngx.exit(ngx.HTTP_FORBIDDEN)
    close_redis(client)
end

local ip_count, err = client:incr(incrKey)
if tonumber(ip_count) == 1 then
    client:expire(incrKey, ip_time_out)
end

if tonumber(ip_count) > tonumber(ip_max_count) then
    client:set(blockKey, 1)
    client:expire(blockKey, ip_block_time)
end

close_redis(client)

Summary

Simple, lightweight configuration with minimal performance impact.

Multiple servers can share the same Redis instance to synchronize the blacklist.

Dynamic updates can be performed manually or via automation by modifying Redis entries.

Application Scenarios

Prevent malicious access such as brute‑force attacks, SQL injection, or XSS.

Block crawlers and data‑scraping bots to reduce load and protect data.

Mitigate DDoS attacks by banning offending IPs.

Rate‑limit specific IPs within a time window to stop abuse.

Advanced Features and Improvements

Automatic anomaly detection and blacklisting based on log analysis.

Whitelist mechanism to allow trusted IPs to bypass restrictions.

CAPTCHA challenges for suspicious IPs.

Statistics and analysis of blacklist data (frequency, duration, etc.) for continuous optimization.

Diagram

IP blacklist architecture diagram
IP blacklist architecture diagram
RedisLuaip blacklist
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

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.