Nginx 白名单放行必须用 allow/deny 指令配合 location 块,rewrite 仅用于重写或跳转,不参与访问控制;需结合 set_real_ip_from 和 real_ip_header 处理代理场景,且规则顺序必须 allow 在前、deny all 在后。

在 Nginx 中,不能直接用 rewrite 指令实现白名单放行——rewrite 专用于 URL 重写或跳转,不处理访问控制。真正做网段白名单放行,必须用 allow/deny 指令配合 location 块;若需“检测+放行+其他动作”,应组合 geo + if + rewrite(仅限必要跳转场景),但核心鉴权仍由 access 模块完成。
白名单逻辑必须靠 allow/deny 实现
rewrite 不参与 IP 判定,也不影响请求是否被允许。Nginx 的访问控制由 ngx_http_access_module 负责,只响应 allow 和 deny 指令。要让特定网段(如办公内网 10.20.0.0/16)放行,其余拒绝,标准写法是:
- 把规则放在
location /或更精确的路径块内(如location /admin) - 按顺序写多个
allow,最后必须加deny all; - 例如:
allow 10.20.0.0/16;
allow 127.0.0.1;
deny all;
}
如果前端有代理,必须还原真实客户端 IP
当请求经过 SLB、CDN 或前置 Nginx 时,$remote_addr 是代理地址,不是真实来源。此时白名单会失效。解决方法是:
- 在
http或server块开头配置信任代理段:
set_real_ip_from 100.64.0.0/10;
real_ip_header X-Forwarded-For; - 注意:
allow/deny仍基于$remote_addr工作,它已被real_ip模块覆盖为真实 IP,无需额外变量 - 验证是否生效:用
curl -H "X-Forwarded-For: 10.20.5.100"测试,看是否能通过
需要 rewrite 配合的典型场景(非鉴权主体)
极少数情况需在放行后触发跳转(如内网用户自动跳转到调试页),可借助 geo 定义标记,再用 if 触发 rewrite:
- 先用
geo标记可信网段:
geo $is_internal {
default 0;
10.20.0.0/16 1;
} - 在 location 中判断并跳转:
if ($is_internal) {
rewrite ^/login$ /debug-login permanent;
} - ⚠️ 注意:
if在 location 内才安全;且 rewrite 是附加动作,白名单本身仍靠allow/deny
常见错误避坑
- 把
allow/deny写在server块顶层(无 location 包裹):部分版本不生效,务必包在location里 - 漏掉
deny all;:未匹配的请求默认放行,白名单形同虚设 - 顺序写反,比如
deny all; allow 10.20.0.0/16;:第一条就拦截了,后面规则永不执行 - 用
rewrite替代访问控制:既不可靠,也无法阻止恶意请求抵达后端


















