可通过set_real_ip_from配合real_ip_header解析x-forwarded-for获取真实ip,再用map指令构建高效黑名单映射,结合if return 403实现可信的精细化访问控制,且支持通过reload热更新黑名单。

通过 proxy_set_header X-Real-IP 和 map 指令配合,可以实现基于真实客户端 IP 的精细化访问控制,尤其适用于多层代理(如 CDN、WAF、负载均衡)后需识别原始请求者并拦截黑名单 IP 的场景。关键在于:**不能直接信任前端传来的 X-Real-IP,而应结合可信代理链与 map 做动态标记和条件拦截。**
确保 X-Real-IP 来源可信:只从已知代理头取值
Nginx 默认不自动设置 X-Real-IP,需由上游代理(如 CDN)注入,或由 Nginx 自己根据可信代理列表解析 X-Forwarded-For。推荐做法是:禁用外部随意设置的 X-Real-IP,仅允许内部可信代理覆盖。
在 http 块中定义可信代理段:
set_real_ip_from 10.0.0.0/8; # 内网 LB set_real_ip_from 192.168.0.0/16; set_real_ip_from 172.16.0.0/12; real_ip_header X-Forwarded-For; real_ip_recursive on;
这样 Nginx 才会正确解析出最外层真实客户端 IP,并存入 $remote_addr(后续可被 proxy_set_header X-Real-IP $remote_addr 透传给后端)。切勿在未设 set_real_ip_from 的情况下直接信任 X-Real-IP 头——攻击者可伪造它绕过拦截。
用 map 构建动态黑名单匹配变量
map 指令在 Nginx 启动时预编译为哈希表,查询效率高,适合做 IP 黑名单快速判断。将真实客户端 IP(即 $remote_addr)映射为一个标志位:
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
map $remote_addr $is_blocked {
default 0;
192.168.1.100 1;
203.0.113.45 1;
2001:db8::1 1;
include /etc/nginx/conf.d/blacklist.map; # 支持外部文件热加载
}注意:map 的 key 必须是完整 IP(不支持 CIDR),如需网段匹配,可用第三方模块(如 ngx_http_geoip2_module)或改用 geo 指令 + map 组合。
在 server 或 location 中拦截黑名单请求
利用 $is_blocked 变量配合 if(仅限于返回状态码等安全操作)或 deny 实现拦截:
- 方式一(推荐):用
if+return返回 403
server {
listen 80;
location / {
if ($is_blocked) {
return 403 "Access denied.";
}
proxy_pass http://backend;
proxy_set_header X-Real-IP $remote_addr; # 透传真实 IP 给后端
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}- 方式二:用
deny+allow(需配合geo)
若黑名单较大且含网段,更适合先用 geo 生成标记,再用 map 转为 0/1,最后用 deny all; allow 127.0.0.1; 配合 if 控制逻辑。
支持热更新黑名单而不重载 Nginx
直接修改 map 文件(如 blacklist.map)后,执行:
nginx -t && nginx -s reload
但频繁 reload 影响性能。更优方案是:用 Lua(OpenResty)或 external binary(如 consul-template + inotify)监听文件变化并触发 reload;或使用 shared memory zone 配合 lua_shared_dict 动态管理黑名单(需 OpenResty)。 纯官方 Nginx 不支持运行时更新 map 内容。










