Backend Development 9 min read

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

This guide explains how to build a dynamic IP blacklist using Nginx, Lua, and Redis, covering installation of LuaJIT, compiling Nginx with required modules, configuring Redis, writing Lua access‑limit scripts, and verifying that frequent requests are automatically blocked for a set period.

Practical DevOps Architecture
Practical DevOps Architecture
Practical DevOps Architecture
Implementing a Dynamic IP Blacklist with Nginx, Lua, and Redis

To prevent malicious crawlers or abusive users from accessing a server, a dynamic IP blacklist is required that rejects requests from IPs listed in the blacklist.

There are several ways to implement an IP blacklist: configuring iptables at the OS level, using Nginx's deny directive or Lua plugins, or checking the client IP in the application layer. This article adopts the Nginx + Lua + Redis architecture to create a Web Application Firewall (WAF) that dynamically blocks frequent IPs.

Install LuaJIT :

[root@hd03 ~]# tar -xf LuaJIT-2.0.5.tar.gz -C /opt/

[root@hd03 ~]# cd /opt/LuaJIT-2.0.5/

[root@hd03 LuaJIT-2.0.5]# make && make install

Set environment variables:

export LUAJIT_LIB=/usr/local/lib

export LUAJIT_INC=/usr/local/include/luajit-2.0

Source the profile and create a symlink for the shared library.

[root@hd03 LuaJIT-2.0.5]# source ~/.bash_profile

[root@hd03 LuaJIT-2.0.5]# ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2

Compile Nginx with required modules (including Lua and Redis support):

[root@hd03 ~]# tar -xf nginx-1.20.2.tar.gz -C /opt/

[root@hd03 nginx-1.20.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --sbin-path=/usr/local/nginx/bin/nginx --conf-path=/usr/local/nginx/conf/nginx.conf --pid-path=/usr/local/nginx/logs/nginx.pid --lock-path=/usr/local/nginx/run/nginx.lock --error-log-path=/usr/local/nginx/logs/error.log --http-log-path=/usr/local/nginx/logs/access.log --http-client-body-temp-path=/var/cache/client_temp --http-proxy-temp-path=/var/cache/proxy_temp --http-fastcgi-temp-path=/var/cache/fastcgi_temp --http-uwsgi-temp-path=/var/cache/uwsgi_temp --http-scgi-temp-path=/var/cache/scgi_temp --with-http_v2_module --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-mail --with-mail_ssl_module --with-file-aio --with-threads --with-stream --with-stream_ssl_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --add-module=/usr/local/ngx_devel_kit-0.3.0 --add-module=/usr/local/lua-nginx-module-0.10.13

[root@hd03 nginx-1.20.2]# make && make install

[root@hd03 nginx-1.20.2]# ln -s /usr/local/nginx/bin/nginx /usr/bin/

Start Nginx:

[root@hd03 nginx-1.20.2]# nginx

Deploy the WAF components :

Install lua-resty-redis module:

[root@hd03 ~]# cd /usr/local/lua-resty-redis

[root@hd03 lua-resty-redis]# make && make install

Install and configure Redis :

[root@hd03 ~]# yum install redis -y

Modify /etc/redis.conf (example settings):

bind 0.0.0.0

daemonize yes

logfile /var/log/redis/redis.log

requirepass 123456

dir /data/redis

Update Nginx configuration to use the WAF :

lua_shared_dict limit 8m;

lua_package_path "lua;/usr/local/nginx/conf/waf/redis.lua;;";

Create access_limit.lua (the script checks request frequency, stores counters in Redis, and adds offending IPs to the blacklist).

Place the script in /usr/local/nginx/conf/waf and test the configuration:

[root@hd03 waf]# nginx -t

Result:

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok

nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

Reload Nginx:

[root@hd03 waf]# nginx -s reload

When a client refreshes the site more than 10 times within one minute, the IP is cached in Redis and automatically blocked for 5 minutes, returning a 403 status code.

Verify in Redis:

Check request count:

redis-cli -h 192.167.16.8 -a 123456

get USER-COUNT-192.167.16.8 → "9" (means 9 hits cached).

Retrieve blacklist set:

smembers limit:ip:blacklist → "192.167.16.8".

Manually add an IP to the blacklist:

sadd limit:ip:blacklist 192.167.16.8

This completes the end‑to‑end setup of a dynamic IP blacklist using Nginx, Lua, and Redis.

backendRedisnginxluawafIP blacklist
Practical DevOps Architecture
Written by

Practical DevOps Architecture

Hands‑on DevOps operations using Docker, K8s, Jenkins, and Ansible—empowering ops professionals to grow together through sharing, discussion, knowledge consolidation, and continuous improvement.

0 followers
Reader feedback

How this landed with the community

login 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.