Nginx 的 ip_hash 本身不支持排除特定 IP,需通过 geo/map 分流或独立 server 块实现白名单绕过:用 geo 标记 + if 分流、map 预设 upstream 名、或为测试设备单独监听端口,确保白名单请求不进入 ip_hash upstream。

Nginx 的 ip_hash 本身不支持“排除某些 IP 不参与哈希”,它会对所有进入 upstream 的请求统一按 $remote_addr 做哈希路由。但你可以通过前置分流 + 条件 proxy_pass的方式,让白名单 IP(如公司测试设备)绕过 ip_hash 逻辑,直连指定后端或走轮询,从而实现“不参与 HASH 固定”。
核心思路是:不让白名单请求进入启用了 ip_hash 的 upstream 块,而是用独立的 proxy_pass 指向目标服务。
✅ 让测试设备跳过 ip_hash 的三种可靠做法
1. 使用 geo 模块标记白名单,配合 if + proxy_pass 分流
在 http 块中定义白名单变量:
geo $skip_ip_hash {
default 0;
192.168.10.5 1; # 测试设备 A
192.168.10.6 1; # 测试设备 B
203.0.113.20 1; # 运维跳板机
}在 server 或 location 中判断并分流:
location / {
if ($skip_ip_hash = 1) {
proxy_pass http://backend_direct; # 单台或轮询 upstream,不启用 ip_hash
proxy_set_header X-Real-IP $remote_addr;
break;
}
proxy_pass http://backend_hashed; # 启用 ip_hash 的 upstream
proxy_set_header X-Real-IP $remote_addr;
}对应 upstream 配置:
upstream backend_hashed {
ip_hash;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
upstream backend_direct {
server 10.0.1.10:8080; # 或配多台走默认轮询
server 10.0.1.11:8080;
}⚠️ 注意:
if在location内可用,但不能嵌套在upstream或server外部直接写proxy_pass;break可终止后续 rewrite,确保不落入其他规则。
2. 利用 map + try_files 实现无 if 的优雅分流(推荐)
避免 if 的潜在陷阱(如与 rewrite/proxy_pass 组合时行为异常),改用 map 预计算目标 upstream 名:
map $remote_addr $upstream_name {
default "backend_hashed";
192.168.10.5 "backend_direct";
192.168.10.6 "backend_direct";
203.0.113.20 "backend_direct";
}
upstream backend_hashed {
ip_hash;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
upstream backend_direct {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}然后 location 中直接引用:
location / {
proxy_pass http://$upstream_name;
proxy_set_header X-Real-IP $remote_addr;
}✅ 优势:语义清晰、无 if 风险、支持热重载。
3. 白名单走独立 server 块(适合隔离强策略场景)
为测试设备单独监听一个端口或 path,完全脱离主流量链路:
server {
listen 8081;
server_name _;
allow 192.168.10.5;
allow 192.168.10.6;
deny all;
location / {
proxy_pass http://backend_direct;
proxy_set_header X-Real-IP $remote_addr;
}
}再让测试设备访问 http://your-domain:8081/,生产用户仍走 :80 的 ip_hash 流程。
? 适用场景:需要对测试流量做独立日志、限流、Header 注入等定制化处理。
❌ 不推荐的做法(常见误区)
在
upstream中用weight=0或down标记白名单 IPip_hash不识别权重,down仅影响健康检查,无法跳过哈希计算。试图用
hash $remote_addr consistent替代ip_hash并排除某些 IPconsistent是 stream 模块专用,HTTP 层不支持;且同样无法动态排除。依赖
X-Forwarded-For做白名单判断
该头可被客户端伪造,必须配合set_real_ip_from+real_ip_header确保$remote_addr可信,否则白名单失效。
? 验证是否生效的小技巧
- 查看 access log 中
upstream_addr字段:白名单请求应显示直连某台后端(如10.0.1.10:8080),而非固定某台; - 对白名单 IP 发连续请求,检查响应 Header 中
X-Upstream(自定义)或后端日志的来源 IP 是否变化; - 临时加日志:
log_format debug '$remote_addr — $upstream_name — $upstream_addr'; access_log /var/log/nginx/debug.log debug;
不复杂但容易忽略:白名单逻辑必须基于真实客户端 IP(即 $remote_addr 已被 real_ip_module 正确还原),否则 CDN 或代理后的 IP 会误判。


















