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

This guide explains how to create a dynamic IP blacklist that blocks malicious or abusive requests by configuring Nginx with Lua scripts and Redis, covering requirements, environment setup, design options, nginx.conf changes, Lua implementation, and the benefits of this lightweight, distributed solution.

Top Architect
Top Architect
Top Architect
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 can set an expiration time for each block.

Environment Preparation

Linux (CentOS7 / Ubuntu etc.)

Redis 5.0.5

Nginx (OpenResty)

Design Options

Three ways to implement an IP blacklist:

OS level using iptables – simple but requires manual updates.

Nginx level using deny or Lua plugins – dynamic and can set expiration, but needs Lua knowledge.

Application level checking the IP before processing – easy to code but may affect performance under high concurrency.

We choose the Nginx + Lua + Redis approach for its dynamic configurability and ability to share the blacklist across multiple servers.

Configure nginx.conf

location / {
    # optional static file check
    # 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;
    alias /usr/local/web/;
    index index.html index.htm;
}

Configure Lua Script

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
local ip_time_out = 1
local ip_max_count = 3

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

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 ip = ngx.req.get_headers()["X-Real-IP"]
    if not ip then ip = ngx.req.get_headers()["x_forwarded_for"] end
    if not ip then ip = ngx.var.remote_addr end
    return ip
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 = client:incr(incrKey)
if tonumber(ip_count) == 1 then
    client:expire(incrKey, ip_time_out)
end
if tonumber(ip_count) > 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 configuration with minimal performance impact, allows multiple servers to share a common blacklist via Redis, and supports dynamic updates and timed expirations.

IP blacklist architecture diagram
IP blacklist architecture diagram
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.

Backendaccess control
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.