nginx默认仅在启动或reload时解析一次proxy_pass中的域名并长期缓存ip,导致ddns或云服务ip变更后持续转发至失效地址;必须配合resolver指令与变量(如set $host "a.com"; proxy_pass http://$host)才能实现实时按需解析,且valid参数控制缓存时效,resolver_timeout保障查询不阻塞。

直接用 resolver 指令解决 Nginx 代理动态域名时的 DNS 缓存问题,核心在于**让 Nginx 在运行时主动解析、按需刷新,而不是只在启动或 reload 时“拍脑袋”记一次 IP 并长期复用**。默认行为下,Nginx 对 proxy_pass http://example.com 这类写法仅解析一次,缓存可能长达数天甚至更久,一旦后端 IP 变更(如云服务扩缩容、CDN 节点切换、DDNS 更新),流量就会持续打到已失效地址,引发大量 Connection refused 或超时。
必须显式配置 resolver 并配合变量使用
仅加一行 resolver 8.8.8.8; 不起作用——Nginx 不会自动对 proxy_pass 中的字面域名生效。关键操作是:
- 在
location块内用set定义一个变量来承载域名,例如set $upstream_host "api.example.com"; - 把
proxy_pass改为指向该变量:proxy_pass https://$upstream_host; - 在同一
location或外层http/server块中声明resolver,例如:resolver 223.5.5.5 114.114.114.114 valid=30s;
这样 Nginx 才会在每次请求到达时,根据变量值触发 DNS 查询,并受 valid 控制缓存时长。不这么做,resolver 就是摆设。
合理设置 valid 时间与超时参数
valid 决定缓存多久,不是越短越好,也不是越长越稳,需结合后端变更频率权衡:
- 云厂商 SLB、K8s Service 等 IP 变更较频繁:设
valid=10s–30s - CDN 回源、稳定性高的 SaaS 接口:可放宽至
valid=2m–5m - 务必配
resolver_timeout 3s;,避免单次 DNS 查询卡住整个请求;低于 2s 易误判丢包,高于 5s 会拖慢首字节时间(TTFB) - 禁用 IPv6 解析(若后端不支持):
ipv6=off,减少冗余查询和失败概率
避开 upstream 域名缓存陷阱
upstream 块里的域名(如 upstream backend { server api.example.com; })默认不走 resolver,仍按启动时解析一次处理。要让它动态更新,有两个选择:
- 放弃
upstream,改用变量 +proxy_pass方式,最简单可靠 - 启用第三方模块(如
nginx-upstream-dynamic-servers),在upstream中加resolve参数:server api.example.com resolve;,但需确认 Nginx 版本兼容性
注意:即使用了 upstream + resolve,也仍需全局配置 resolver,否则模块无法工作。
验证与调试不能跳过
上线前必须确认 DNS 解析是否真正按预期刷新:
- 在响应头中加入调试信息:
add_header X-Upstream-Addr $upstream_addr always;,观察实际转发的 IP 是否随时间变化 - 检查 error.log 是否出现
resolver timed out或host not found,说明 DNS 服务器不可达或配置错误 - 用
dig @223.5.5.5 api.example.com对比 Nginx 日志中的 IP,确认是否一致且及时更新 - 模拟后端 IP 变更(如修改本地 hosts 或临时调整 DNS 返回),观察 Nginx 是否在
valid时间后自动切到新地址











