一、问题描述

        本人遇到的问题是通过阿里云公网服务器上的nginx反代到公司内网服务(此内网服务通过ddns发布到外网,ip是动态的),当公司内网服务对应的IP发生变化时,外网访问会出现nginx报错,

nginx dns缓存如何配置 nginx dns缓存定时更新_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;
  }
}