在执行proxy_pass时,如何每次强制nginx解析DNS(动态主机名)?


52

我正在使用在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是多少?
lunixbochs 2011年

我的ddns上的TTL是60s,dyndns.com的默认值
xiamx 2011年


Answers:


8

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

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


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

1
根据该文件,有一个特殊的上游server标志resolve,这只是在商业版本(见nginx.org/en/docs/http/ngx_http_upstream_module.html#server
omribahumi

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

90

在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年

不,请阅读源代码。In such setup ip address of "foo.example.com" will be looked up dynamically and result will be cached for 5 minutes.为了清楚起见,我将其添加到了答案中。
ohaal 2015年

13
在花了我大部分时间后-在具有nginx 1.1.19的Ubuntu 12.04上,set内部location无法正常工作。当心
omribahumi

此解决方案与我一起使用,但是在5分钟的TTL中找不到参考。nginx.org/en/docs/http/ngx_http_core_module.html#resolver By default, nginx caches answers using the TTL value of a response. An optional valid parameter allows overriding it: resolver 127.0.0.1 [::1]:5353 valid=30s;
Montaro

4
注意:对于docker,它的DNS解析器位于127.0.0.11,因此对于开发,我使用此方法:resolver 127.0.0.11 [::1]:5353 valid=15s;
Dalibor Filus

9

最可靠的注释和ohaal答案中包含有价值的信息。

但是我认为重要的是要提及2016年发布的nginx官方文章,它清楚地解释了nginx在此问题上的行为以及可能的解决方案:https : //www.nginx.com/blog/dns-service-discovery-nginx-plus /

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

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

PS:本来可以发表评论,但积分还不够...


1

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

0

我整理了一个脚本来监视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=$1

[ -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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.