OpenResty+Redis是实现Nginx动态黑白名单的最优方案,需配置lua_shared_dict共享内存、init_worker_by_lua_file定时全量加载Redis黑名单,并在access_by_lua_file中内存级检测IP后ngx.exit(403)拦截。

可以通过 Nginx 的 map 指令 + 共享内存区域(shared memory zone)或外部存储(如 Redis、文件)实现后端接口的访问控制名单共享,但需注意:Nginx 本身不原生支持跨 worker 进程的动态名单热更新与共享写入。最实用、稳定且可扩展的方式是「Nginx + Redis」组合,配合 ngx_http_redis2_module 或更推荐的 lua-resty-redis(OpenResty 环境),实现统一、实时、集群友好的黑白名单控制。
使用 OpenResty + Lua 实现动态名单校验
OpenResty 内置 Lua 环境,可灵活对接 Redis 查询 IP/Token/路径等维度的访问权限,所有 Nginx worker 共享同一份 Redis 数据,天然支持多实例部署下的名单一致性。
- 安装 OpenResty(含 lua-resty-redis),启用
lua_shared_dict做本地缓存,降低 Redis 压力 - 在
http块中定义共享字典:lua_shared_dict ip_acl_cache 10m; - 在
location中用access_by_lua_block拦截请求:
先查本地缓存 → 缓存未命中则查 Redis → 根据返回值(如"allow"/"deny")调用ngx.exit(403) - 名单管理通过独立服务(如 Admin API)写入 Redis(例如 key:
acl:ip:192.168.1.100,value:allow),支持 TTL 自动过期
纯 Nginx(无 Lua)的轻量替代方案
若无法引入 OpenResty,可用 Nginx 原生命令配合定期同步的静态名单文件,适用于变更不频繁、容忍分钟级延迟的场景。
- 维护一个 ACL 列表文件(如
/etc/nginx/conf.d/acl_ips.conf),格式为:map $remote_addr $is_allowed {<br> default 0;<br> 192.168.1.100 1;<br> 2001:db8::1 1;<br>} - 在
http块中include该文件,并在location中用if ($is_allowed = 0) { return 403; } - 更新名单时,用脚本生成新文件 +
nginx -t && nginx -s reload,reload 会平滑加载新 map,不影响已有连接 - 缺点:每次 reload 会创建新 worker,旧 worker 逐步退出,不适合高频更新;且无法按请求头、参数等复杂条件匹配
结合 upstream 实现后端粒度控制
若需对不同后端接口(如 /api/v1/users vs /api/v1/admin)应用不同名单,可在 proxy 阶段前完成鉴权,并将结果透传给后端(如加 header)。
- 用 Lua 根据
$request_uri或$http_x_api_key查对应策略键(如acl:group:admin) - 允许时设置
proxy_set_header X-Auth-Status "granted";,供后端二次校验或审计 - 拒绝时直接返回 403,不转发请求,减轻后端压力
- 可扩展支持 JWT 解析、速率限制联动(如名单内用户限 100r/m,名单外限 10r/m)
关键注意事项
无论采用哪种方式,都需关注实效性、性能和可观测性。
- Redis 方案务必设置连接池和超时(如
set_timeout(100)),避免阻塞 Nginx 事件循环 - 本地缓存(
lua_shared_dict)建议设合理 TTL(如 30s),平衡一致性与性能 - 记录被拦截的请求(
log_by_lua)到独立 access log,便于安全审计与名单优化 - 禁止在
if中使用复杂变量或嵌套逻辑 —— Nginx 的if是“陷阱区”,应优先用 Lua 替代


















