一、背景
在当今的网络环境中,恶意攻击、爬虫滥用、DDoS 攻击等问题屡见不鲜,严重影响着服务器的安全和稳定运行。静态 IP 黑名单由于无法实时更新,难以应对不断变化的网络威胁。而采用 Nginx + Lua + Redis 组合实现的动态 IP 黑名单方案,能够实时更新黑名单,有效阻挡恶意 IP 的访问,为服务器安全保驾护航。本文将详细介绍这一方案的实现过程。
二、架构选择
在这个动态 IP 黑名单方案中,Nginx、Lua 和 Redis 各自扮演着重要角色。
- Nginx:作为高性能的 Web 服务器和反向代理服务器,能够高效处理大量并发请求。它负责接收客户端请求,并在处理请求前通过嵌入的 Lua 脚本检查客户端 IP 是否在黑名单中。
- Lua:一种轻量级脚本语言,具有简洁、高效的特点。嵌入 Nginx 后,可编写灵活的逻辑来实现 IP 检查、与 Redis 交互等功能,扩展 Nginx 的能力。
- Redis:高性能的 key-value 数据库,支持快速的读写操作,非常适合存储黑名单数据。它能实时存储和更新黑名单 IP,保证 Nginx 能快速查询到最新的黑名单信息。

三、实现步骤
安装 OpenResty(含 Nginx 和 Lua 模块)
OpenResty 是基于 Nginx 扩展的 Web 平台,内置了 Lua 模块,方便实现复杂业务逻辑。
1.添加 OpenResty 仓库:
对于 CentOS 系统,执行以下命令:
yum install -y yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
对于 Ubuntu 系统,执行以下命令:
apt-get update
apt-get install -y software-properties-common
add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"
apt-get update
2.安装 OpenResty
CentOS 系统:yum install -y openresty
Ubuntu 系统:apt-get install -y openresty
安装完成后,启动 OpenResty 服务:systemctl start openresty,
并设置开机自启:systemctl enable openresty。
4.安装 Redis
- 对于 CentOS 系统,执行:yum install -y redis
- 对于 Ubuntu 系统,执行:apt-get install -y redis-server
- 启动 Redis 服务:systemctl start redis,设置开机自启:systemctl enable redis。
- 验证 Redis 是否安装成功,执行 redis-cli ping,若返回 PONG,则表示安装成功。
配置 Nginx
- 找到 OpenResty 的 Nginx 配置文件,通常位于 /usr/local/openresty/nginx/conf/nginx.conf。
- 在 http 块中添加以下配置,用于定义 Lua 脚本路径和 Redis 连接信息:
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
lua_shared_dict ip_blacklist 10m; # 定义共享内存,用于缓存黑名单,可选
server {
listen 80;
server_name your_domain.com; # 替换为你的域名或服务器 IP
location / {
access_by_lua_file /usr/local/openresty/nginx/conf/lua/ip_blacklist.lua; # 指定 Lua 脚本路径
proxy_pass http://backend_server; # 替换为你的后端服务地址
}
}
创建 Lua 脚本存放目录:mkdir -p /usr/local/openresty/nginx/conf/lua。
编写 Lua 脚本
在 /usr/local/openresty/nginx/conf/lua 目录下创建 ip_blacklist.lua 脚本,内容如下:
-- 获取客户端 IP
local client_ip = ngx.var.remote_addr
if not client_ip then
ngx.log(ngx.ERR, "无法获取客户端 IP")
return ngx.exit(500)
end
-- 连接 Redis
local redis = require "resty.redis"
local red = redis:new()
-- 设置 Redis 连接超时时间
red:set_timeout(1000) -- 1 秒
-- 连接 Redis 服务器,替换为你的 Redis 地址和端口
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "连接 Redis 失败: ", err)
-- 此处可根据需求决定是否允许请求继续,这里选择允许
return
end
-- 检查 IP 是否在黑名单中,假设黑名单的 key 为 "ip_blacklist"
local is_blacklisted, err = red:sismember("ip_blacklist", client_ip)
if err then
ngx.log(ngx.ERR, "查询 Redis 失败: ", err)
red:close()
return
end
-- 关闭 Redis 连接
local ok, err = red:set_keepalive(10000, 100) -- 设置连接池,10 秒超时,最多 100 个连接
if not ok then
ngx.log(ngx.ERR, "设置 Redis 连接池失败: ", err)
end
-- 如果 IP 在黑名单中,拒绝请求
if is_blacklisted == 1 then
ngx.log(ngx.WARN, "客户端 IP ", client_ip, " 在黑名单中,拒绝请求")
return ngx.exit(403)
end
-- IP 不在黑名单中,允许请求继续
ngx.log(ngx.INFO, "客户端 IP ", client_ip, " 不在黑名单中,允许请求")
代码解释:
- 首先获取客户端 IP 地址,如果获取失败则记录错误并返回 500 错误。
- 然后创建 Redis 连接对象,设置连接超时时间并连接 Redis 服务器。
- 连接成功后,使用 sismember 命令查询客户端 IP 是否在名为 “ip_blacklist” 的集合中。
- 操作完成后,将 Redis 连接放入连接池,提高性能。
- 如果 IP 在黑名单中,返回 403 错误拒绝请求;否则允许请求继续处理。
Redis 黑名单管理
添加黑名单IP
使用 Redis 命令往 “ip_blacklist” 集合中添加 IP:
redis-cli
sadd ip_blacklist 192.168.1.100 # 添加单个 IP
sadd ip_blacklist 192.168.1.101 192.168.1.102 # 添加多个 IP
删除黑名单IP
redis-cli
srem ip_blacklist 192.168.1.100 # 删除单个 IP
查看黑名单IP
redis-cli
smembers ip_blacklist # 查看所有黑名单 IP
scard ip_blacklist # 查看黑名单 IP 数量
设置黑名单过期(可选)
如果需要让黑名单 IP 在一段时间后自动失效,可以结合 Redis 的过期键功能。例如,单独记录每个 IP 的过期时间,定期清理:
# 添加 IP 时设置过期时间为 1 小时(3600 秒)
set ip:192.168.1.100 blacklisted EX 3600
# 定期执行脚本将过期的 IP 从黑名单集合中移除
测试验证
正常IP测试
使用客户端 IP 不在黑名单中的机器,执行 curl http://your_domain.com,应能正常获取响应。
黑名单IP测试
- 将测试机器的 IP 添加到黑名单:redis-cli sadd ip_blacklist 测试机器IP
- 执行 curl http://your_domain.com,应返回 403 Forbidden 错误。
- 查看 Nginx 日志(通常位于 /usr/local/openresty/nginx/logs/error.log),应有类似 “客户端 IP 测试机器 IP 在黑名单中,拒绝请求” 的记录。
- 从黑名单中移除该 IP:redis-cli srem ip_blacklist 测试机器IP
- 再次执行 curl http://your_domain.com,应能正常获取响应。
注意事项
- Redis 高可用性:在生产环境中,应使用 Redis 集群或主从复制,确保 Redis 服务的高可用,避免因 Redis 故障导致整个黑名单功能失效。
- 性能优化:可利用 Nginx 的共享内存缓存黑名单数据,减少对 Redis 的频繁查询,提高性能。但要注意缓存更新策略,保证数据一致性。
- Lua 脚本安全:Lua 脚本具有较高的权限,编写时要注意输入验证,防止注入攻击。
- 黑名单更新频率:根据实际业务需求调整黑名单的更新频率,既要及时阻挡恶意 IP,又要避免频繁操作影响性能。
- 日志监控:定期查看 Nginx 和 Redis 的日志,及时发现异常情况,如频繁的黑名单拦截、Redis 连接失败等。
总结
通过 Nginx + Lua + Redis 实现动态 IP 黑名单,充分利用了 Nginx 的高性能、Lua 的灵活性和 Redis 的快速读写能力,能够实时、高效地阻挡恶意 IP 的访问。该方案易于实现和扩展,可根据实际需求进行定制,如结合防火墙、入侵检测系统等进一步增强服务器的安全性。在实际应用中,需注意各组件的配置优化和高可用性保障,确保方案稳定可靠运行。




