proxy_pass含变量时nginx每次请求动态dns解析,需配置resolver(多dns+valid+timeout),避免变量拼接错误,推荐用map预定义或upstream配合变量。

Nginx 的 proxy_pass 指令中如果用了变量(比如 $host、$scheme、$arg_backend 等),会导致域名解析行为与静态配置完全不同——Nginx 不再在启动时或重载时解析后端地址,而是在每次请求时动态解析。这带来两个关键问题:DNS 查询阻塞、缓存缺失、甚至解析失败导致 502。
下面分三块说清楚怎么处理:
proxy_pass 含变量时的 DNS 解析机制
当 proxy_pass 写成带变量的形式,例如:
location /api/ {
proxy_pass http://$arg_upstream$request_uri;
}
或
location / {
proxy_pass http://$host:8080;
}
Nginx 就会:
- 放弃预解析(即不走
resolver静态缓存或 upstream 预定义) - 每次转发前调用系统
getaddrinfo()或内置 resolver 发起 DNS 查询 - 若未显式配置
resolver,默认使用系统/etc/resolv.conf,但不支持 DNS 缓存、超时控制、重试机制 - 查询失败直接返回
502 Bad Gateway
必须显式配置 resolver 并设合理参数
仅写 resolver 8.8.8.8; 是不够的。要稳定运行,需配合 resolver_timeout 和 valid(DNS 缓存有效期):
# 推荐写法(放在 http 或 server 块顶层) resolver 114.114.114.114 223.5.5.5 valid=30s; resolver_timeout 5s;
说明:
- 至少指定两个可靠 DNS 服务器(避免单点故障)
-
valid=30s表示 DNS 结果缓存 30 秒,减少重复查询 -
resolver_timeout 5s控制单次 DNS 查询最大等待时间,防止卡住 worker 进程
⚠️ 注意:resolver 不能写在 location 块里,必须在 http、server 或 location 的上级作用域。
避免变量拼接引发的协议/端口/路径错误
变量拼接容易出错,常见坑:
-
$host可能带端口(如example.com:8080),拼进http://$host就变成http://example.com:8080:8080 -
$scheme是http或https,但后端未必支持对应协议 -
$request_uri已含 query string,若proxy_pass末尾带/会触发重写,造成路径重复
安全写法建议:
- 用
map提前校验和规范变量值:map $arg_backend $backend_host { default "localhost"; "user" "user-svc.default.svc.cluster.local"; "order" "order-svc.default.svc.cluster.local"; } upstream dynamic_backend { server $backend_host:8080; } - 或改用
upstream+variables(需搭配resolver):resolver 114.114.114.114; upstream dynamic { server $backend_host:8080; } location / { set $backend_host $arg_host; proxy_pass http://dynamic; }
不复杂但容易忽略











