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

This guide explains how to create a dynamic IP blacklist using Nginx, Lua scripts, and Redis, covering requirements, environment setup, design options, Nginx configuration, Lua implementation, summary of benefits, and possible extensions for advanced security scenarios.

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

Requirement

To block certain crawlers or malicious users, we need a dynamic IP blacklist that denies service to listed IPs and allows setting an expiration time for the ban.

Environment Preparation

Linux distribution: CentOS 7 / Ubuntu etc.

Redis version: 5.0.5

Nginx version: OpenResty

Design Scheme

There are three main ways to implement an IP blacklist:

Operating‑system level – configure iptables. Simple but requires manual changes on the server.

Web‑server level – use Nginx deny or Lua plugins for dynamic blocking. Flexible but needs Lua knowledge.

Application level – check the client IP in application code before processing the request. Easy to maintain but may affect performance under high concurrency.

We choose the Nginx + Lua + Redis architecture for easy management and sharing of the blacklist.

Configure nginx.conf

location / {
    # If static resources, you can add a condition
    #if ($request_uri ~ .*\\.(html|htm|jpg|js|css)) {
    #    access_by_lua_file /usr/local/lua/access_limit.lua;
    #}
    access_by_lua_file /usr/local/lua/access_limit.lua;  # apply rate‑limit logic
    alias /usr/local/web/;
    index index.html index.htm;
}

Configure Lua Script

-- /usr/local/lua/access_limit.lua
local pool_max_idle_time = 10000   -- connection pool idle timeout (ms)
local pool_size = 100               -- connection pool size
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              -- time window for counting (seconds)
local ip_max_count = 3             -- max requests in the 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
    ok, err = client:auth(redis_auth)
    if not ok then errlog("failed to auth: ", err); return end
elseif err then
    errlog("failed to get reused times: ", err); return
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 clientIP = getIp()
local incrKey = "limit:count:" .. clientIP
local blockKey = "limit:block:" .. clientIP

local is_block = 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

The Nginx + Lua + Redis solution provides a lightweight, easily configurable IP blacklist with minimal performance impact, supports sharing across multiple servers via Redis, and allows dynamic updates either manually or through automation.

Simple configuration with low overhead.

Shared blacklist across servers through Redis.

Dynamic updates possible via scripts or automation.

Extension

1. IP Blacklist Use Cases

Prevent malicious access – block IPs attempting brute‑force, SQL injection, XSS, etc.

Stop crawlers and data abuse – limit aggressive scraping.

Mitigate DDoS attacks – deny IPs launching large‑scale attacks.

Rate limiting – restrict request frequency from a single IP.

2. Advanced Features

Anomaly detection & auto‑ban – analyze logs to automatically block suspicious IPs.

Whitelist mechanism – allow trusted IPs to bypass the blacklist.

CAPTCHA verification – challenge high‑frequency IPs.

Statistics & analysis – track block counts, durations, and refine policies.

Continuous improvement of the IP blacklist enhances server and application security.

IP blacklist architecture
IP blacklist architecture
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

redisip blacklist
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.