nginx 中 location 块可通过 if 指令配合 $remote_addr 或 $http_x_forwarded_for 实现基于源 ip 的分流,需用正则精确匹配、加 break 防 fallthrough,并推荐用 map 指令替代以提升性能与健壮性。

在 Nginx 中,location 块本身不直接支持基于源 IP 的判断,但可以通过配合 if 指令和内置变量(如 $remote_addr 或 $http_x_forwarded_for)在 location 内实现 IP 分流。关键在于:分流逻辑写在 location 内部,用正则匹配源 IP 特征,再通过 proxy_pass 转发到不同 upstream。
使用 $remote_addr 匹配客户端真实 IP
当 Nginx 直连客户端(未经过代理),$remote_addr 就是真实来源 IP。可按以下方式做精确或范围匹配:
- 匹配末段为特定数字:例如末位是 0、2、6 →
if ($remote_addr ~* \.[026]$) { proxy_pass http://backend-a; break; } - 匹配末段区间:例如末段 1–125 →
if ($remote_addr ~* \.(?:1[0-9][0-9]|1[0-2][0-5]|[1-9][0-9]|[1-9])$) { ... }(注意:正则[1,125]是错误写法,Nginx 不支持这种简写,必须用标准正则表达式) - 匹配固定网段:例如 192.168.202.* →
if ($remote_addr ~* ^192\.168\.202\.) { proxy_pass http://backend-a; break; }
处理代理环境:用 $http_x_forwarded_for 取真实 IP
如果 Nginx 前面有 CDN 或负载均衡器,$remote_addr 会变成代理 IP。此时需依赖 $http_x_forwarded_for,但要注意该头可被伪造,仅建议在可信内网中使用:
- 取第一个 IP(防伪造):
set $real_ip $http_x_forwarded_for;+if ($real_ip ~* ^(112\.18\.96\.) ) { ... } - 更稳妥做法:结合
real_ip_module模块,在http块中配置set_real_ip_from和real_ip_header X-Forwarded-For,让$remote_addr自动还原为真实客户端 IP
分流逻辑必须加 break 且避免 fallthrough
if 块内执行 proxy_pass 后,必须跟 break,否则会继续执行后续指令;同时 location 中不能遗漏兜底转发,否则未匹配请求可能 500 或 404:
- 正确结构:先
if匹配并proxy_pass + break,最后一条proxy_pass作为默认后端 - 错误写法:多个
if并列但无break,或漏掉最终proxy_pass,会导致请求无响应 - 注意:
if在location中虽可用,但属于“非标准上下文”,Nginx 官方建议谨慎使用;高并发场景优先考虑map指令预定义分流规则
推荐替代方案:用 map 实现高效 IP 分流
比嵌套 if 更健壮、性能更好,适合复杂分流策略:
- 在
http块中定义:map $remote_addr $upstream_backend { default "backend-b"; ~^192\.168\.202\. "backend-a"; ~\.[026]$ "backend-a"; } - 在
location中直接:proxy_pass http://$upstream_backend; -
map支持正则、前缀、默认值,且一次匹配、零开销,reload 即生效,无if的潜在副作用











