OpenResty需用Lua脚本加载IP黑白名单并缓存至shared dict以提升性能,支持文件监听、Redis Pub/Sub或HTTP接口热更新,在access_by_lua_block中按黑名单>白名单>默认策略顺序匹配拦截。

用 Lua 脚本加载和刷新 IP 黑白名单
OpenResty 本身不内置持久化黑白名单,需通过 Lua 脚本主动读取外部数据源(如本地文件、Redis、HTTP 接口),并在请求处理阶段实时匹配。关键在于避免每次请求都重复读取或解析——应利用 shared dict 缓存名单,并配合定时任务或信号触发更新。
用 shared dict 缓存名单提升性能
将 IP 名单加载到 Nginx 共享内存中,可实现跨 worker 进程共享、毫秒级查询。示例代码:
-- 初始化 shared dict(在 init_by_lua_block 中) lua_shared_dict ip_whitelist 10m; lua_shared_dict ip_blacklist 10m;
在 Lua 中检查并缓存:
- 首次访问时,调用
ngx.shared.ip_whitelist:get_keys()判断是否为空;若为空,从文件/Redis 加载并写入 shared dict - 使用
set(key, value, exptime)写入,value 可为 true 或时间戳,exptime 控制缓存有效期 - 查询时直接
get("192.168.1.100"),返回非 nil 即命中
支持热更新:文件监听 or 定时拉取
无需重启 OpenResty 即可更新名单:
-
文件方式:用
resty.timer.at每 30 秒检查文件 mtime,变化则重新读取解析(适合中小规模、低频变更) -
Redis 方式:用
resty.redis连接,订阅 Pub/Sub 频道(如ip:whitelist:update),收到消息后立即 reload 名单 -
HTTP 接口方式:后端提供
/api/v1/ip-lists?group=whitelist,Lua 用resty.http异步拉取 JSON,解析后批量写入 shared dict
在 access 阶段拦截请求
把 IP 匹配逻辑放在 access_by_lua_block,早于 upstream 转发:
access_by_lua_block {
local ip = ngx.var.remote_addr
local white = ngx.shared.ip_whitelist:get(ip)
local black = ngx.shared.ip_blacklist:get(ip)
<pre class="brush:php;toolbar:false;">if black then
return ngx.exit(403)
end
if white and not white == true then
-- 可扩展:白名单带过期时间,这里做校验
return ngx.exit(403)
end
if not white then
-- 不在白名单且无黑名单规则,默认放行;也可设默认 deny
end}
注意:黑白名单逻辑优先级要明确(例如黑名单 > 白名单 > 默认策略),避免误拦或漏拦。











