Wie kann man Nginx zwingen, DNS (eines dynamischen Hostnamens) jedes Mal aufzulösen, wenn proxy_pass ausgeführt wird?

52

Ich verwende Nginx / 0.7.68 unter CentOS mit der folgenden Konfiguration:

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

Es proxy_passhandelt sich um einen DNS-Eintrag, dessen IP sich häufig ändert. Nginx speichert die veraltete IP-Adresse im Cache und fordert die falsche IP-Adresse an.

Wie kann ich verhindern, dass Nginx die IP-Adresse zwischenspeichert, wenn sie veraltet ist?

xiamx
quelle
Wenn Sie die Nginx-Quelle durchsehen, scheint es, dass Nginx hartcodiert ist, um Auflösungen für ihre TTL zwischenzuspeichern. Wie lautet die TTL für Ihre dynamischen DNS?
Lunixbochs
TTL auf meinen ddns ist 60s, der Standardwert von dyndns.com
xiamx

Antworten:

8

Es ist eine faszinierende Frage und AFAIK, die nicht gut funktionieren wird. Sie können versuchen, das Upstream- Modul zu verwenden und anhand der Anweisungen für das Failover zu überprüfen, ob es als Hack funktioniert.

2018 edit: vieles hat sich geändert. Überprüfen Sie die Antwort von @ohaal , um echte Informationen zu erhalten.

Core-Dump
quelle
1
überraschenderweise hat alles wie erwartet geklappt, als ich zu upstream gewechselt bin. Ich werde dies dann als richtige Antwort markieren
xiamx
1
Laut Dokumentation gibt es ein spezielles Upstream- serverFlag resolve, das nur in der kommerziellen Version verfügbar ist (siehe nginx.org/en/docs/http/ngx_http_upstream_module.html#server )
omribahumi
1
@gansbrest diese Seite scheint eine Art Spam-Seite zu sein? Ich bitte Sie, Ihre Antwort zu entfernen.
Majikman
90

Die akzeptierte Antwort hat bei mir unter nginx / 1.4.2 nicht funktioniert.

Die Verwendung einer Variablen proxy_passerzwingt eine Neuauflösung der DNS-Namen, da NGINX Variablen anders als statische Konfigurationen behandelt. Aus der NGINX- proxy_passDokumentation :

Parameterwert kann Variablen enthalten. In diesem Fall wird bei Angabe einer Adresse als Domänenname der Name in den beschriebenen Servergruppen gesucht und, falls nicht gefunden, mit einem Resolver ermittelt.

Zum Beispiel:

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

Hinweis: Ein Resolver (dh der zu verwendende Nameserver) MUSS verfügbar und konfiguriert sein, damit dies funktioniert (und Einträge in einer /etc/hostsDatei werden bei einer Suche nicht verwendet).

Standardmäßig wird die Cache-Zeit in Version 1.1.9 oder höher von NGINX-Cache-Antworten mit dem TTL-Wert einer Antwort und einem optionalen validParameter überschrieben:

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

Vor Version 1.1.9 war das Einstellen der Caching-Zeit nicht möglich, und nginx hat die Antworten immer für die Dauer von 5 Minuten zwischengespeichert. .

ohaal
quelle
Würde dies nicht eine DNS-Abfrage bei jeder einzelnen Anfrage erzwingen? Das klingt nach schrecklicher Leistung ...
Lucascaro
Nein, lies die Quelle. In such setup ip address of "foo.example.com" will be looked up dynamically and result will be cached for 5 minutes.Ich habe es der Klarheit halber zur Antwort hinzugefügt.
Ohaal
13
Nachdem ich den größten Teil meines Tages damit verbracht habe - auf Ubuntu 12.04 mit nginx 1.1.19 - funktioniert setinside locationnicht richtig. Vorsicht
Omribahumi
Diese Lösung hat bei mir funktioniert, ich konnte jedoch keine Referenz für die 5-Minuten-TTL finden. 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
Hinweis: Für Docker befindet sich der DNS-Resolver bei 127.0.0.11. Für die Entwicklung verwende ich daher Folgendes:resolver 127.0.0.11 [::1]:5353 valid=15s;
Dalibor Filus
9

Es gibt wertvolle Informationen in Gansbrest Kommentar und Ohaal Antwort.

Ich halte es jedoch für wichtig, diesen 2016 veröffentlichten offiziellen Nginx-Artikel zu erwähnen, der das Verhalten von Nginx in dieser Angelegenheit und die möglichen Lösungen klar erläutert: https://www.nginx.com/blog/dns-service-discovery-nginx-plus /

Wir müssen in der Tat "den Domain-Namen in eine Variable setzen" und die Resolver- Direktive verwenden.

Die Verwendung einer Variablen ändert jedoch das Umschreibeverhalten. Möglicherweise müssen Sie die Rewrite-Direktive verwenden. Dies hängt von Ihrem Standort und der Proxy_Pass-Konfiguration ab.

PS: hätte einen Kommentar gepostet aber noch nicht genug Punkte ...

Jack B.
quelle
1

Ohaals Antwort trifft die meisten von uns dort, aber es gibt einen Fall, in dem der DNS-Resolver nicht unter 127.0.0.1 läuft (z. B. wenn Sie sich in einer speziellen containerisierten Umgebung befinden).

In diesem Fall möchten Sie möglicherweise die Nginx-Konfiguration auf ändern resolver ${DNS_SERVER};. Führen Sie dann vor dem Start von nginx Folgendes aus

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
Wonton
quelle
0

Ich habe ein Skript gehackt, um einen Ordner conf.d auf DNS-Änderungen zu überprüfen und nginx bei Erkennung neu zu laden. Es ist ein erster Durchgang und kann sicherlich verbessert werden (im nächsten Durchgang werde ich nginx -T verwenden, um Upstreams speziell zu analysieren. Dieselbe Idee könnte für proxy_pass-Direktiven verwendet werden):

#!/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
Mushuweasel
quelle