openresty+lua+redis是nginx网关层最实用可控的ip封禁方案,毫秒级实时判断、黑名单增删无需reload、支持自动封禁与ttl自动解封。

直接在 Nginx 网关层做 IP 封禁,最实用、最可控的方式就是用 OpenResty + Lua + Redis。它不依赖日志轮询或系统防火墙,每次请求毫秒级判断,黑名单增删实时生效,无需 reload,适合生产环境高频管理。
为什么选 OpenResty 而不是原生 Nginx
原生 Nginx 的 deny 指令只能静态写死 IP,改一次就得 nginx -s reload,高并发下 reload 有连接中断风险;geo + map 方式虽可外挂文件,但同样要 reload 才生效。OpenResty 内置 LuaJIT 和 resty.redis 模块,能把 Redis 查询嵌入到请求生命周期的任意阶段(比如 access_by_lua*),真正实现“写入即封禁”。
核心配置三步走
• 在 http 块中初始化 Redis 连接池(避免每次请求新建连接):
init_by_lua_block {<br>
local redis = require "resty.redis"<br>
local red = redis:new()<br>
red:set_timeout(100)<br>
red:connect("127.0.0.1", 6379)<br>
-- 可选:设置密码 red:auth("yourpass")<br>
ngx.ctx.redis_pool = red<br>
}
• 在目标 location 中调用封禁逻辑:
location / {<br>
access_by_lua_block {<br>
local red = ngx.ctx.redis_pool<br>
local ip = ngx.var.remote_addr<br>
if red:get("blacklist:" .. ip) == "1" then<br>
return ngx.exit(403)<br>
end<br>
}<br>
proxy_pass http://backend;<br>
}
• 封禁操作只需一条 Redis 命令:redis-cli SETEX "blacklist:192.168.1.100" 3600 "1"
其中 3600 是封禁秒数,过期自动清除,不用人工清理。
真实场景增强建议
• 获取真实客户端 IP:优先读 X-Real-IP 或 X-Forwarded-For,再 fallback 到 remote_addr,避免代理后取错 IP
• 自动封禁高频访问者:在 Lua 脚本里加计数逻辑,比如 1 分钟内请求超 100 次就自动写入黑名单,无需人工干预
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
• 配合管理接口:用 Spring Boot 或 Python FastAPI 写个简单 HTTP 接口,接收 POST /api/block?ip=1.2.3.4&ttl=1800,内部执行 Redis 操作,运维或安全平台可直接调用
• 日志留痕:封禁时用 ngx.log(ngx.WARN, "Blocked IP: ", ip) 记入 Nginx error log,方便事后审计
验证与调试技巧
• 本地测试:用 curl -H "X-Real-IP: 1.2.3.4" http://your-domain.com/ 模拟指定 IP 请求
• 快速清空测试:执行 redis-cli KEYS "blacklist:*" | xargs redis-cli DEL
• 查看当前黑名单:执行 redis-cli KEYS "blacklist:*",确认 key 存在且 TTL 正常
• 检查 Lua 报错:翻 error.log,常见问题是 Redis 连接失败、语法错误或变量未定义










