Nginx可通过map+外部文件热重载、geo模块+定时更新、OpenResty+Lua实时查询、njs轻量判断四种方式实现动态ACL,无需重启服务,各适配不同频率与复杂度场景。

Nginx 本身不提供原生的“内部 API”来动态更新访问控制列表(ACL),但可以通过组合标准模块与外部协作机制,实现类似效果。核心思路是:让 Nginx 在运行时按需加载或查询 ACL 规则,避免重启服务。以下几种实用方式可满足不同场景需求。
使用 map 指令 + 外部文件热重载
适用于规则变化不频繁、允许短时延迟(秒级)的场景。Nginx 支持 map 指令将变量映射为值,并能配合 include 引入外部配置片段。
- 新建一个独立文件(如
/etc/nginx/conf.d/acl.map),内容为:
在主配置中引用:
include /etc/nginx/conf.d/acl.map;server {
if ($allowed = 0) { return 403; }
# 其他配置...
}
- 更新 ACL 后,执行
nginx -s reload即可生效;若用log_format或access_log记录匹配过程,便于调试 - 注意:
if在 location 外使用有局限,建议包裹在location块内,或改用deny/allow配合geo模块
结合 geo 模块 + 定时更新文件
geo 模块比 map 更适合 IP 白/黑名单管理,支持 CIDR 和范围匹配,且性能更优。
- 创建
/etc/nginx/conf.d/ip_blacklist.conf:
再配合脚本定期生成 dynamic_blacklist.conf(例如从数据库或 API 拉取最新黑名单),然后触发 nginx -s reload。也可用 inotifywait 监听文件变化自动 reload。
通过 Lua 模块调用外部 HTTP 接口(OpenResty)
若已部署 OpenResty(含 ngx_lua),可实现实时 ACL 查询,无需 reload:
- 在
location中嵌入 Lua 逻辑:
access_by_lua_block {
local http = require "resty.http"
local client = http:new()
local res, err = client:request_uri("http://acl-service/check?ip=" .. ngx.var.remote_addr, {
timeout = 1000
})
if not res or res.status ~= 200 then
ngx.exit(403)
end
}
# 正常代理或返回内容
}
- 需确保 ACL 服务高可用、低延迟;建议加缓存(如
lua_shared_dict)减少重复请求 - 生产环境务必设置超时和降级策略(如缓存失效时默认放行或拒绝)
利用 njs(Nginx JavaScript)做轻量级动态判断
Nginx 0.4.0+ 内置 njs,适合简单逻辑,不依赖第三方模块:
- 编写
/etc/nginx/js/acl.js:
const ip = r.variables.remote_addr;
// 可读取本地 JSON 文件或调用 fetch(需启用 experimental fetch)
if (ip === '192.168.10.20') {
r.return(403);
}
}
在配置中启用:
js_import /etc/nginx/js/acl.js;location /api {
js_content acl.checkACL;
}
- njs 的
fetch当前为实验特性,生产建议搭配本地缓存或预加载机制 - 适合规则条目少、更新频率低、且不想引入 OpenResty 的场景


















