Nginx upstream 中写死域名会导致DNS解析不更新,必须用变量+resolver实现动态解析;proxy_pass引用变量时才触发resolver,valid=10s覆盖DNS TTL;upstream原生不支持,可选第三方模块、proxy_pass变量模式或Lua脚本方案。

直接在 upstream 块里写域名(比如 server api.example.com;),Nginx 启动时只解析一次,之后永远不更新——哪怕 DNS 已指向新 IP,流量仍打向旧地址,导致 502 或连接超时。这不是配置遗漏,而是 Nginx 的默认行为:静态解析、零刷新。
必须用变量触发 resolver 动态解析
resolver 指令本身不会自动监听域名变化。它只在 proxy_pass 使用变量 且该变量在运行时可求值时才被调用。
- ✅ 正确写法:在 location 内定义变量,再 proxy_pass 引用
proxy_pass https://$backend;
- ❌ 错误写法:即使上面写了 resolver,写死域名也无效
- resolver 必须和变量处于同一作用域或外层(如 server 块内声明 resolver,location 内用变量)
- valid=10s 是你强制设定的缓存有效期,不是照搬 DNS TTL;设了 valid 就以它为准
upstream 场景下无法直接用 resolver?换方案
原生 upstream 不支持动态 DNS 解析。若必须用 upstream 结构,有三个可靠替代路径:
- 用第三方模块
nginx-upstream-dynamic-servers:在 upstream 中加resolve参数,依赖 DNS TTL 自动刷新(需验证 Nginx 版本兼容性) - 改用
proxy_pass + 变量模式:放弃 upstream,用多个 location 或 map 匹配不同后端,每个走独立变量 proxy_pass - 接入 Lua 脚本(如 ngx_http_lua_module):在 content_by_lua_block 中调用
ngx.socket.udp或resty.dns手动解析并设置变量,灵活性最高
验证是否真正生效
不能只看配置有没有写 resolver,要确认实际行为:
- 执行
nginx -T | grep 'proxy_pass'看是否输出的是域名还是已解析的 IP(输出 IP 说明没走变量路径) - 用
ss -tnp | grep :443观察长连接目标 IP 是否随 DNS 变更而更新 - 临时把 DNS 解析结果改成一个新 IP,等 valid 时间过后发起请求,检查 error.log 是否出现新 IP 的连接日志
主动清除缓存应对故障切换
当健康检查发现后端不可达,可立即清空对应域名的 DNS 缓存,避免等待 valid 过期:
- 配置
proxy_intercept_errors on和error_page 502 = @purge_dns - 在
@purge_dnslocation 中用 Lua 调用ngx.shared.dns_cache:delete(ngx.var.backend) - 随后重试请求,触发新一轮 resolver 解析


















