Nginx通过map指令按客户端IP段动态路由,核心是将$remote_addr或$realip_remote_addr映射为后端地址变量并在proxy_pass中引用,需在http块定义、支持CIDR/正则/精确匹配、必须设default防502,且proxy_pass末尾不可加路径。

用 Nginx 的 map 指令按客户端 IP 段动态路由,核心是把 $remote_addr 或 $realip_remote_addr 映射为后端地址变量,再在 proxy_pass 中引用。它不依赖第三方模块,配置简洁,适合做地域分流、内网灰度、白名单透传等场景。
IP 段匹配要写在 http 块里,不能放 server 里
map 必须定义在 http{} 全局块中,Nginx 启动时就完成变量注册,运行时只查表,无性能损耗。匹配依据用 $remote_addr(直连时)或 $realip_remote_addr(经可信代理后)。若用了 real_ip 模块,记得先配置 set_real_ip_from 和 real_ip_header。
支持三种匹配方式:
- 精确 IP:
"192.168.1.100" "10.0.1.10:8080"; - IP 段(CIDR):
"192.168.1.0/24" "10.0.1.20:8080";(需 Nginx ≥ 1.19.0) - 正则表达式:
~^10\.0\.2\.[0-9]{1,3}$ "10.0.2.50:8080";(注意转义点号)
务必加 default 分支,否则未匹配的请求会因变量为空导致 502 错误。
典型配置:按办公网、测试网、默认集群分发
例如公司内网 192.168.10.0/24 走预发布环境,测试团队网段 172.16.5.0/24 走 canary 集群,其余走生产集群:
http {
map $remote_addr $backend_ip {
default "10.0.4.100:8080"; # 生产
"192.168.10.0/24" "10.0.2.10:8080"; # 办公网 → 预发布
"172.16.5.0/24" "10.0.3.20:8080"; # 测试网 → canary
~^127\.0\.0\.1$ "127.0.0.1:8000"; # 本地调试
}
<pre class='brush:php;toolbar:false;'>server {
listen 80;
location /api/ {
proxy_pass http://$backend_ip;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}}
注意:proxy_pass 后不能带路径(如 http://$backend_ip/),否则原始 URI 会被丢弃;正确写法是末尾不加 /,让后端自己处理完整路径。
进阶技巧:组合 IP + 请求头做双重决策
单一 IP 匹配有时不够灵活,可叠加一层逻辑。比如优先看 X-Forwarded-For 中的真实 IP,缺失时回退到 $remote_addr:
map $http_x_forwarded_for $client_ip {
"" $remote_addr;
default $http_x_forwarded_for;
}
<p>map $client_ip $backend_group {
default "prod";
"192.168.1.0/24" "staging";
"~^10.10." "canary";
}再配合 upstream 分组使用,就能对不同 IP 段启用差异化策略——比如 staging 组开启详细日志,canary 组加权重控制流量比例。
注意事项和常见问题
IP 段匹配不是万能的,有几个关键限制得清楚:
- Nginx 不做健康检查,后端宕机只会返回 502;如需自动剔除,得配合上游服务发现或自建探活脚本
- CIDR 匹配在旧版 Nginx(
- 若前端有 CDN 或多层代理,
$remote_addr是上一跳地址,必须用real_ip模块还原真实客户端 IP - 所有匹配值都是静态字符串,无法拼接变量或执行函数,复杂逻辑建议前置到网关或业务层



















