我正在使用在CentOS上运行的nginx / 0.7.68,配置如下:

server {
    listen       80;
    server_name ***;
    index index.html index.htm index.php default.html default.htm default.php;

    location / {
            root   /***;
            proxy_pass   http://***:8888;
            index  index.html index.htm;
    }
    # where *** is my variables


proxy_pass到IP频繁变化的DNS记录。 Nginx缓存过期的IP地址,从而导致对错误IP地址的请求。

如何在过期时如何阻止Nginx缓存IP地址?

评论

查看nginx来源,似乎确实对nginx进行了硬编码以缓存其TTL的解析-动态DNS上的TTL是什么?

我的ddns上的TTL是60秒,dyndns.com的默认值

另请参见stackoverflow.com/questions/26956979/…

相关:serverfault.com/questions/560632/…

#1 楼

这是一个有趣的问题,并且AFAIK不能正常工作。您可以尝试使用上游模块,并使用指令进行故障转移,以查看其是否可以作为黑客使用。

2018编辑:发生了很多变化。查看@ohaal的答案以获得有关此内容的真实信息。

评论


令人惊讶的是,当我转到上游时,一切都按预期进行。然后,我将其标记为正确答案

–xiamx
2011-2-27在22:20

根据文档,有一个特殊的上游服务器标志解析,仅在商业版本中可用(请参阅nginx.org/en/docs/http/ngx_http_upstream_module.html#server)

–omribahumi
15年7月19日在13:48

@gansbrest该网站似乎是垃圾邮件网站?我想请您删除您的回复。

– majikman
18年6月28日在0:02

令人遗憾的是,到2020年,上游模块仍无法解决此问题。一次解析地址并永远使用该地址是没有用的。

–菲尔
20年9月3日在8:23

#2 楼

在nginx / 1.4.2。上,已接受的答案对我不起作用。

proxy_pass中使用变量会强制重新解析DNS名称,因为NGINX将变量与静态配置不同地对待。从NGINX proxy_pass文档:


参数值可以包含变量。在这种情况下,如果将地址指定为域名,则在描述的服务器组中搜索该名称,如果找不到,则使用解析器确定该名称。


例如:

server {
    ...
    resolver 127.0.0.1;
    set $backend "http://dynamic.example.com:80";
    proxy_pass $backend;
    ...
}


注意:解析器(即要使用的名称服务器)必须可用并且已配置为可以正常工作(而/etc/hosts文件中的条目将不可用)

默认情况下,版本1.1.9或更高版本的NGINX缓存使用响应的TTL值和可选的valid参数回答,从而可以覆盖缓存时间:

resolver 127.0.0.1 [::1]:5353 valid=30s;


在版本1.1.9之前,无法调整缓存时间,nginx始终将答案缓存5分钟。.

评论


这不会在每个请求上强制进行dns查询吗?听起来像是糟糕的表现...

–lucascaro
2015年3月10日,下午3:42

不,请阅读源代码。在这种设置中,将动态查找“ foo.example.com”的ip地址,并将结果缓存5分钟。为了清楚起见,我将其添加到了答案中。

–ohaal
2015年3月10日在9:43

在花了我大部分时间后-在具有nginx 1.1.19的Ubuntu 12.04上,设置内部位置无法正常工作。谨防

–omribahumi
15年7月19日在13:38

注意:对于docker,它的DNS解析器位于127.0.0.11,因此对于开发人员,我使用此解析器:解析器127.0.0.11 [:: 1]:5353 valid = 15s;

– Dalibor Filus
18年6月1日在11:18

这是一个令人讨厌的陷阱,让我整整一天都无法调试:如果在proxy_pass指令中使用变量,则路径的解释会更改。执行此操作时,原始请求的路径将被完全覆盖,并替换为proxy_pass中给定的路径。您必须使用url中没有路径的proxy_pass以避免这种行为。

– Sam Svenbjorgchristiensensen
20年3月2日在1:02

#3 楼



但是最重要的评论和ohaal答案中都提供了有价值的信息。但是,我认为提及此官方的nginx文章很重要,该文章发表于2016年,它清楚地解释了nginx在此问题上的行为以及可能的解决方案:
https://www.nginx.com/blog/dns-service-discovery-nginx-plus/

我们确实必须“在变量中设置域名”并使用resolver指令。

但是,使用变量会更改重写行为。您可能必须使用rewrite指令,这取决于您的位置和proxy_pass设置。

PS:会发表评论,但积分不足...

#4 楼

ohaal的答案将我们大多数人带到了那里,但是在某些情况下,DNS解析器无法使用127.0.0.1(例如,当您处于特殊的容器化环境中)
在这种情况下,您可能需要更改nginx conf到resolver ${DNS_SERVER};。然后,在启动nginx之前,运行
export DNS_SERVER=$(cat /etc/resolv.conf |grep -i '^nameserver'|head -n1|cut -d ' ' -f2)
envsubst '${DNS_SERVER}' < your_nginx.conf.template > your_nginx.conf

注意,您需要安装gettext软件包,因为它提供了envsubst命令。

#5 楼

我已经整理了一个脚本来监视conf.d文件夹上游的dns更改,并在检测到时重新加载nginx。这是第一步,肯定可以改进(下一遍,我将使用nginx -T专门解析上游。相同的想法可以用于proxy_pass指令):

#!/bin/bash

get_upstreams() {
  local files=$@
  grep -hEo '(server\s+)[^:;]+' $files | cut -d' ' -f 2
}

resolve_hosts() {
  local hosts=$@
  for h in $hosts; do dig +short $h; done | sort -u
}

watch_dir=

[ -d $watch_dir ] || exit 2

upstreams=$(get_upstreams $watch_dir/*)
ips=$(resolve_hosts $upstreams)
if [ ! "$ips" ]; then
  echo "Found no resolvable hosts in $watch_dir files."
fi

host_hash=$(echo $ips | /usr/bin/sha512sum)

echo $host_hash
echo $ips

while [ -d $watch_dir ]; do
  sleep 30
  upstreams=$(get_upstreams $watch_dir/*)
  ips=$(resolve_hosts $upstreams)
  new_hash=$(echo $ips | /usr/bin/sha512sum)
  if [ "$host_hash" != "$new_hash" ]; then
    echo Detected an upstream address change.  $ips
    echo Reloading nginx
    echo $new_hash
    echo $ips
    /sbin/service nginx reload
    host_hash=$new_hash
  fi
done