nginx中proxy_pass写死域名会导致dns仅启动时解析,需配合resolver和变量(如set $upstream "xxx"; proxy_pass https://$upstream;)或upstream resolve才能实现动态dns更新。

直接在 proxy_pass 里写死域名(比如 proxy_pass https://api.example.com;),Nginx 只会在启动或重载时解析一次 DNS,之后所有请求都发往缓存下来的 IP。哪怕后端 IP 已变更、DNS TTL 过期、甚至域名已下线,Nginx 也完全无感——这是生产环境中最隐蔽却高频引发 502 或连接超时的根源。
为什么加了 resolver 还是不生效?
很多人配了 resolver 8.8.8.8 valid=10s;,却发现日志里仍是旧 IP,连接没切换。根本原因在于:resolver 指令本身不会自动作用于字面量域名。它只是“备好了解析器”,但 Nginx 默认对 proxy_pass http://xxx.com; 这类写法,压根不会调用这个解析器,而是走启动时的静态 getaddrinfo() 路径。
真正触发 resolver 的唯一方式是:proxy_pass 的值必须是一个变量,哪怕只是简单赋值:
set $upstream "api.example.com";proxy_pass https://$upstream;
只有这时,Nginx 才会在每次需要建立新连接(或缓存过期后)调用 resolver 指定的 DNS 服务器去查记录。变量是开关,resolver 是工具,缺一不可。
resolver 放在哪?valid 时间怎么设?
作用域必须匹配:resolver 需出现在与变量同级或更外层的块中。常见错误是把它写在 http 块顶层,但在 location 里用变量,结果因版本兼容性(尤其旧版)导致不生效。稳妥做法是直接放在 location 或 server 块内:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
location /api/ {
resolver 114.114.114.114 8.8.8.8 valid=15s;
set $backend "api.example.com";
proxy_pass https://$backend;
}
valid 参数决定刷新节奏:它不是 DNS TTL 的搬运工,而是你给 Nginx 缓存结果设定的“保质期”。设为 15s 表示最多 15 秒后下次请求会重新查 DNS;设为 300s 就几乎退化成静态解析。
- 云服务扩缩容、CDN 回源切流等场景,建议 10–30 秒
- 内网稳定服务可放宽至 60 秒
比变量 + resolver 更稳的方案:upstream resolve
Nginx 1.19.9+ 原生支持 resolve 参数,这是面向生产环境的推荐写法:
- 在
http块定义全局resolver:resolver 1.1.1.1 valid=10s; - 用
upstream显式管理后端:upstream origin_pool { server origin.example.com:443 resolve; } - 代理时直接引用:
proxy_pass https://origin_pool;(注意协议需匹配)
这样 Nginx 会按 valid 时间间隔主动轮询 DNS,自动剔除失效 IP,并支持 SRV 记录和多 A/AAAA 记录负载均衡,还天然兼容 keepalive 和健康检查逻辑。
验证是否真正生效
不能只看配置有没有写,得靠实际行为确认:
- 查
error.log,搜索resolving、could not be resolved或no resolver defined类报错 - 用
ss -tnp | grep :443或lsof -i :443观察 worker 进程实际连接的目标 IP 是否随 DNS 更新而变化 - 临时将回源域名 DNS TTL 设为 5 秒,在变更 IP 后观察 Nginx 连接是否在
valid时间内切换 - 加响应头辅助调试:
add_header X-Upstream-Addr $upstream_addr always;
不复杂但容易忽略。










