Nginx SNI Docker Swarm环境下后端服务无法重新解析问题
我来帮你排查这个Nginx TCP转发的DNS解析问题——这种上游容器重启后无法重新解析的情况,我之前也遇到过几次,主要是因为Nginx在stream模块下的DNS缓存和连接复用逻辑和http模块有点不一样,咱们一步步来解决:
1. 检查Resolver的配置位置与参数
你当前把resolver放在server块里虽然可行,但更建议放在stream全局块中,确保所有TCP转发服务都能复用这个DNS配置。另外,需要补充ipv6=off参数(如果你的上游没有IPv6服务),避免Nginx解析到无效的IPv6地址导致连接失败:
stream { # 使用公共DNS或你的内部DNS服务器,valid=30s确保缓存30秒后重新解析 resolver 8.8.8.8 valid=30s ipv6=off; server { listen 443; ssl_preread on; # 确保$name是从SNI正确获取的上游主机名 set $name $ssl_preread_server_name; proxy_pass $name:443; } }
注意:必须通过变量(比如$name)传递上游地址,Nginx才会在每次请求时触发DNS重新解析;如果直接写固定域名,Nginx只会在启动时解析一次。
2. 调整连接超时与复用设置
上游容器重启后,Nginx可能还在复用之前建立的长连接,导致连接拒绝错误。你需要添加连接超时配置,并禁用不必要的长连接:
server { listen 443; ssl_preread on; set $name $ssl_preread_server_name; proxy_pass $name:443; # 缩短连接超时,让Nginx更快发现连接失败并触发重新解析 proxy_connect_timeout 5s; # 设置整体请求超时 proxy_timeout 30s; # 禁用HTTP长连接,避免复用失效的连接(如果上游是HTTP服务) proxy_http_version 1.1; proxy_set_header Connection ""; }
3. 验证DNS解析有效性
在Nginx服务器上手动执行DNS解析,确认上游容器重启后,DNS服务器能返回新的IP地址:
dig your-upstream-domain.com nslookup your-upstream-domain.com
如果DNS解析正常,但Nginx还是用旧IP,可能是Nginx的DNS缓存没有正确刷新——你可以尝试发送USR1信号让Nginx重新加载配置并刷新缓存:
nginx -s reload # 或者强制刷新缓存 kill -USR1 $(cat /var/run/nginx.pid)
4. 检查Nginx版本兼容性
部分旧版本的Nginx(比如低于1.19.0)在stream模块的DNS动态解析上存在bug,建议升级到最新的稳定版(比如1.24.x系列),很多这类解析问题在新版本中已经被修复。
最后验证
上游容器重启后,等待30秒(你的valid配置时间),然后测试连接。如果还是有问题,可以查看Nginx的错误日志(通常在/var/log/nginx/error.log),看是否有更详细的DNS解析错误信息,方便进一步排查。
内容的提问来源于stack exchange,提问作者thewire247




