一、问题描述
本人遇到的问题是通过阿里云公网服务器上的nginx反代到公司内网服务(此内网服务通过ddns发布到外网,ip是动态的),当公司内网服务对应的IP发生变化时,外网访问会出现nginx报错,。查看nginx的error日志,出现“connect() failed (110: Connection timed out) while connecting to upstream, client: 58.22.113.106”类似错误。上网发现此类问题是由于Nginx的DNS缓存导致的。
nginx version: nginx/1.14.1
OS:CentOS Linux release 8.5.2111
二、问题分析
经过前后三次反复出现该问题的跟踪,发现确实是每次ddns域名对应的IP变化后,就出现该问题,所以确定是DNS缓存问题。过程中排查手段如下:
# 使用如下命令查看ddns域名当前的IP
dig @8.8.8.8 "A.com" +short
# 查看报错日志中实际解析的IP,具体是下面命令查出日志行upstream对应的地址里
tail -fn100 /var/log/nginx/error.log |grep "110: Connection timed out"
# 出现该问题软重启nginx可以立马重新对配置文件里的域名进行重新解析,恢复正常
nginx -s reload
这里引用自己在解决该问题过程中参考的其中一篇文章《Nginx反向代理DNS缓存问题》,文章中介绍了两种解决方案,甚至有其他文章说到了三种解决方案。本人在解决自己的实际问题过程中也尝试过三种方案才有效果。
三、问题解决
大家可以查看《问题分析》里引用的文章,这里我把自己尝试的方案顺序也在贴一次。
1、upstream结合max_fails、fail_timeout
该方案经过测试并未解决我的问题,问题第二天还是发生了。
upstream A {
least_conn;
server A.com:8080 max_fails=1 fail_timeout=10s;
}server{
……
location / {
proxy_pass https://A;
}}
2、resolver + resolver_timeout
该方案也没能解决问题,问题重复发生。默认接口
server{
……
resolver 114.114.114.114 8.8.8.8 valid=10s;
resolver_timeout 3s;location / {
proxy_pass https://A.com:28080;
}}
3、1+2
该方案同样没有解决我的问题,问题再次发生。
upstream A {
least_conn;
server A.com:8080 max_fails=1 fail_timeout=10s;
}server{
……
resolver 114.114.114.114 8.8.8.8 valid=10s;
resolver_timeout 3s;location / {
proxy_pass https://A;
}}
4、proxy_pass中使用变量(该方案需要结合resolver才生效)
开始尝试第4中方案,该方案成功解决问题。经过长期观察,我这里使用该方案当转发的域名DDNS出来的IP变化时, 第一次访问还是会出现nginx错误页,然后日志里报错为“A.com could not be resolved (110: Operation timed out)”,但是再访问就正常了。如果哪位大牛知道怎么彻底修复这个问题,麻烦留言告知,不甚感激!
刚开始只是在proxy_pass中使用变量,nginx -s reload后访问直接报nginx错误,一看error.log发现“no resolver defined to resolve A.com”,然后才加上resolver配置,最后Nginx对应修改的配置如下:
server{
resolver 114.114.114.114 8.8.8.8 valid=10s;
resolver_timeout 3s;location / {
set $upstream_param "A.com:28080";
proxy_pass https://$upstream_param;
}}
5、补充一种引用方案(本人因为环境特殊并未验证)
需要安装nginx模块nginx-upstream-dynamic-servers或ngx_upstream_jdomain,可实现动态dns解析。
nginx-upstream-dynamic-servers配置如下,具体可以参考其官网(测试环境nginx1.24.0 + nginx-upstream-dynamic-servers 0.4.0编译make报错,放弃。改用jdomain可以编译成功)
http { resolver 8.8.8.8; upstream example { server example.com resolve; } }
原文链接:https://blog.csdn.net/yangfande362/article/details/129560366