nginx用allow+deny all实现ip白名单,需allow在前、deny all在后,且仅在http/server/location块生效;注意代理ip、健康检查ip及geo指令替代方案。

用 allow 和 deny 实现 IP 白名单最直接
Nginx 没有原生“白名单模式”开关,但靠 allow + deny all 组合就能达成效果。关键不是“加白”,而是“先放行、再全拒”。顺序不能错,allow 必须写在 deny all 前面,否则所有请求都会被拦在第一步。
实操建议:
- 把规则写在
location块里(比如只限制后台接口),而不是整个server块,避免误杀静态资源或健康检查路径 - 单个 IP 写成
allow 192.168.1.100;,IP 段写成allow 10.0.0.0/8; - 如果用的是云服务器,注意真实客户端 IP 可能被 SLB 或 CDN 覆盖,此时要配合
real_ip_header和set_real_ip_from使用,否则allow判的只是代理 IP
遇到 403 Forbidden 却没生效?检查这三处
常见错误不是规则写错,而是位置或上下文不对。Nginx 的访问控制指令只在 http、server、location 三个作用域生效,且不支持 if 块内嵌套。
典型失效场景:
-
allow放在if ($request_uri ~* "/admin") { ... }里 —— 直接忽略,语法合法但不执行访问控制 - 配置了多个
location,但只在其中一个写了白名单,其他 location 仍可自由访问 - 启用了
auth_basic,而allow/deny在认证之后才校验,导致未授权用户也能触发 403,但原因其实是认证失败而非 IP 拒绝
想用 CIDR 或域名做白名单?geo 指令更可靠
allow 不支持域名匹配,也不支持动态加载 IP 列表。geo 指令可以提前把 IP 映射为变量值,再结合 map 或 if 控制响应,适合管理大量白名单或需要分组策略的场景。
例如:
geo $remote_addr $is_allowed {
default 0;
192.168.1.0/24 1;
2001:db8::/32 1;
}
然后在 location 中:
if ($is_allowed = 0) {
return 403;
}
注意:geo 匹配的是 $remote_addr,同样受代理影响;若需基于 X-Forwarded-For 判断,必须先用 set_real_ip_from 设置可信源,再改用 $realip_remote_addr。
HTTPS 站点下白名单突然失效?别漏掉健康检查探针
很多运维会忽略负载均衡器或容器平台(如 Kubernetes Ingress、阿里云 SLB)的主动健康检查。它们通常用固定 IP(比如 100.64.0.1 或内网段)发起 GET /healthz 请求。如果白名单没包含这些地址,Nginx 会返回 403,导致整站被判定为异常下线。
排查方法:
- 查 Nginx access log,过滤出 403 请求,看来源 IP 是什么
- 确认 LB 的健康检查配置中使用的路径、Host 头、源 IP 段
- 把对应探测 IP 或网段显式加进
allow列表,哪怕只是临时加一条allow 100.64.0.0/10;
真实环境里,白名单逻辑常卡在“谁才是真正客户端”这个点上,而不是语法本身。每次加完规则,务必用 curl -v --interface 模拟不同源 IP 测试,别只信本地 localhost。











