Die DNS-Auflösung in Nginx ist einer dieser Punkte, die man oft erst dann ernst nimmt, wenn ein Reverse Proxy plötzlich mit 502 antwortet. Der nginx resolver bestimmt, wie Nginx Hostnamen zur Laufzeit auflöst, wie lange Antworten zwischengespeichert werden und wann eine Anfrage an einem fehlenden DNS-Eintrag scheitert. Genau darum geht es hier: welche Rolle der Resolver spielt, wann er wirklich nötig ist und wie ich ihn in der Praxis sauber konfiguriere.
Die wichtigsten Punkte zur DNS-Auflösung in Nginx
- Der Resolver definiert die DNS-Server, die Nginx bei Laufzeitauflösung verwenden darf.
- Besonders wichtig wird er, wenn in
proxy_passVariablen vorkommen und der Zielhost erst zur Request-Zeit feststeht. - Nginx cached DNS-Antworten standardmäßig gemäß TTL; mit
valid=lässt sich diese Zeit begrenzen. -
resolver_timeoutist mit 30 Sekunden voreingestellt, in internen Setups ist ein kürzerer Wert oft praktischer. - Standardmäßig fragt Nginx A- und AAAA-Records ab;
ipv4=offoderipv6=offhelfen bei klaren IPv4- oder IPv6-Umgebungen.

Wann Nginx einen Resolver wirklich braucht
Der wichtigste Denkfehler ist aus meiner Sicht, DNS-Auflösung und Upstream-Auswahl gleichzusetzen. Nginx kann mit festen Zielen sehr gut arbeiten, aber sobald der Zielhost erst während der Anfrage entsteht, braucht er eine explizite DNS-Instanz, an die er sich wenden darf. Genau an dieser Stelle entscheidet sich, ob die Konfiguration stabil bleibt oder in produktiven Situationen unnötig fragil wird.
Praktisch lässt sich das gut trennen:
| Situation | Resolver nötig | Einordnung |
|---|---|---|
IP-Adresse in proxy_pass
|
Nein | Direktes Ziel ohne DNS-Auflösung. |
Fester Backend-Name als upstream-Gruppe |
Meist nein | Sauber für stabile Ziele und klaren Betrieb. |
Hostname in proxy_pass mit Variablen |
Ja | Nginx löst zur Laufzeit auf und braucht dafür einen Resolver. |
| Backend-Name ändert sich häufig | Ja | Sinnvoll, wenn DNS bewusst Teil der Laufzeitlogik ist. |
Wenn ein Domainname mehrere Adressen liefert, verwendet Nginx diese im Round-Robin-Verfahren. Das ist nützlich, solange die Zieladressen wirklich gleichwertig sind. Genau deshalb lohnt sich eine minimale Konfiguration, die nur das tut, was die jeweilige Umgebung tatsächlich braucht.
Die richtige Minimal-Konfiguration
Für die Grundkonfiguration reicht oft schon sehr wenig. Ich setze gern einen internen oder lokalen Resolver ein und ergänze nur die Parameter, die den Betrieb tatsächlich robuster machen. Die offizielle Nginx-Dokumentation empfiehlt ausdrücklich, DNS-Server in einem gesicherten, vertrauenswürdigen lokalen Netz zu betreiben, und das halte ich in produktiven Umgebungen ebenfalls für die richtige Haltung.
Ein kompakter Startpunkt kann so aussehen:
resolver 127.0.0.1 10.0.0.53 valid=30s ipv6=off;
resolver_timeout 5s;Die Teile daran sind absichtlich schlicht gehalten:
-
resolverdefiniert die DNS-Server. Mehrere Einträge werden im Round-Robin abgefragt. - Wenn kein Port angegeben ist, verwendet Nginx den DNS-Port 53.
-
valid=30sbegrenzt die Cachezeit in Nginx auf 30 Sekunden, auch wenn der DNS-Record länger leben würde. -
ipv6=offschaltet AAAA-Abfragen ab, wenn die Zone nur IPv4 liefern soll. -
resolver_timeout 5ssorgt dafür, dass eine DNS-Störung nicht zu lange auf eine Anfrage durchschlägt.
Für stabile internen Dienste reicht oft ein langer Cache, für volatile Umgebungen mit schnellen Deployments oder wechselnden Backends ist ein kürzeres Fenster sinnvoller. Genau diese Unterscheidung macht später den Unterschied zwischen „funktioniert meistens“ und „bleibt unter Last berechenbar“.
Warum Variablen in proxy_pass den Unterschied machen
Der zweite entscheidende Punkt ist proxy_pass. Sobald dort Variablen auftauchen, verschiebt sich die Namensauflösung in die Laufzeit. Das ist technisch sauber, aber eben nur dann, wenn der Resolver auch wirklich definiert ist und die Konfiguration den Pfad zur Zieladresse nicht unnötig verkompliziert.
set $backend app.internal.example;
location /api/ {
proxy_pass http://$backend;
}In so einer Konstellation muss Nginx den Hostnamen während der Anfrage auflösen. Wenn der Name nicht bereits über eine beschriebene Server-Gruppe abgedeckt ist, greift Nginx auf den Resolver zurück. Genau deshalb taucht die bekannte Fehlermeldung in der Praxis fast immer dann auf, wenn jemand dynamische Zieladressen mit einer statischen DNS-Annahme kombiniert.
Ich trenne deshalb Zielhost und URI nach Möglichkeit sauber. Der Hostname gehört in die Auflösungslogik, die Pfadlogik in die Location- oder Rewrite-Regeln. Sobald beides vermischt wird, werden Fehler schwerer zu lesen und die spätere Wartung unnötig teuer.
Wenn ich feste Backends habe, verwende ich lieber eine upstream-Gruppe:
upstream app_backend {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
location /api/ {
proxy_pass http://app_backend;
}Das ist in vielen Setups die robustere Variante, weil Nginx das Ziel intern kennt und die Konfiguration klarer bleibt. Dynamische DNS-Namensauflösung ist dann nur noch dort nötig, wo sie fachlich wirklich Sinn ergibt. Genau da liegt für mich die saubere Grenze zwischen Reverse-Proxy-Logik und Service-Discovery.
TTL, valid und resolver_timeout richtig abstimmen
Die eigentliche Kunst ist nicht, DNS irgendwie zum Laufen zu bringen, sondern das Zeitverhalten passend zu wählen. Nginx cached Antworten standardmäßig anhand der TTL aus dem DNS-Record. Mit valid= kannst du diese Cachezeit übersteuern, und mit resolver_timeout begrenzt du, wie lange Nginx überhaupt auf eine Antwort wartet.
| Einstellung | Wirkung | Praktischer Einsatz |
|---|---|---|
| DNS-TTL | Nginx übernimmt die Gültigkeit aus der Antwort | Gut, wenn die DNS-Zone sauber gepflegt ist. |
valid=30s |
Begrenzt die Cachezeit in Nginx | Sinnvoll bei dynamischen oder schnell wechselnden Backends. |
resolver_timeout 5s |
Maximale Wartezeit pro Namensauflösung | Verhindert lange Hänger bei DNS-Problemen. |
Als Startwerte nehme ich häufig 30 Sekunden für valid und 2 bis 5 Sekunden für resolver_timeout. Kürzere Zeiten machen die Konfiguration nervös und erzeugen unnötigen DNS-Verkehr, längere Zeiten verzögern Änderungen am Backend. Beides ist nicht automatisch falsch, aber beides muss zur Änderungsfrequenz der Umgebung passen.
Wenn sich Ziele nur selten ändern, kann ein längeres Cachefenster völlig vernünftig sein. Bei Blue-Green-Deployments, Autoscaling oder kurzlebigen Containern würde ich deutlich aggressiver auf Aktualität gehen. Der Punkt ist nicht, eine magische Zahl zu finden, sondern die DNS-Schicht an die Betriebsrealität anzupassen.
IPv4, IPv6 und Sicherheitsgrenzen
Standardmäßig fragt Nginx beim Auflösen sowohl IPv4- als auch IPv6-Adressen ab. Das ist in Dual-Stack-Umgebungen sauber, kann aber unnötig werden, wenn die DNS-Zone nur eine Adressfamilie bereitstellt. Dann lohnt es sich, bewusst zu begrenzen, statt beide Wege pauschal offen zu lassen.
| Fall | Option | Effekt |
|---|---|---|
| IPv4-only-Zone | ipv6=off |
Keine unnötigen AAAA-Abfragen. |
| IPv6-only-Zone | ipv4=off |
Keine unnötigen A-Abfragen. |
| Dual-Stack | Standardverhalten | Beide Adressfamilien werden berücksichtigt. |
Für mich gehört auch die Sicherheitsfrage dazu. DNS ist im Proxy-Pfad kein unsichtbares Detail, sondern eine echte Vertrauenskomponente. Ich halte Resolver deshalb möglichst intern, am besten in einem stabilen und kontrollierten Netzsegment. Genau in diese Richtung geht auch die offizielle Nginx-Dokumentation, wenn sie vor DNS-Spoofing warnt und ein vertrauenswürdiges lokales Umfeld empfiehlt.
Wenn der Resolver selbst wackelt oder zu weit außerhalb der eigenen Kontrolle liegt, wird die Fehlersuche schnell unangenehm: Dann sieht es nach einem Upstream-Problem aus, obwohl die eigentliche Ursache schon eine Schicht früher liegt. Das ist einer der Gründe, warum ich DNS in Nginx nie als bloßes Komfortfeature behandle.
Typische Fehler, die ich in der Praxis zuerst prüfe
Bei Störungen gehe ich fast immer dieselbe Reihenfolge durch. Erst prüfe ich, ob überhaupt ein dynamischer Hostname im Spiel ist, dann ob ein Resolver definiert wurde, und danach, ob Zeitfenster und Adressfamilien zur Zielumgebung passen. Diese drei Fragen lösen in der Praxis erstaunlich viele 502er und „funktioniert nur manchmal“-Effekte auf.
- Kein Resolver definiert - fast immer ein Hinweis darauf, dass ein Hostname erst zur Laufzeit aufgelöst werden soll, Nginx dafür aber keinen DNS-Server kennt.
-
Falscher Scope - der Resolver muss in einem Kontext stehen, den die betroffene
locationtatsächlich erbt. - Zu langes Cachefenster - der Backend-Wechsel ist schon passiert, Nginx spricht aber noch gegen die alte Adresse.
- Zu kurzer Cache - unnötig viele DNS-Anfragen und mehr Empfindlichkeit gegenüber kleinen DNS-Störungen.
- Falsche Adressfamilie - die Zone liefert nur A oder nur AAAA, Nginx fragt aber die andere Familie mit ab.
- Zu großzügiger Timeout - eine DNS-Störung blockiert Anfragen länger als nötig.
Ich prüfe bei Verdacht außerdem immer die Fehlerlogs und den konkreten Aufbau von proxy_pass. Oft steckt der Fehler nicht im DNS selbst, sondern in einer Variable, die zur falschen Zeit ausgewertet wird. Wenn man das einmal verstanden hat, sind die meisten Fehlersituationen erstaunlich klar lesbar.
Eine robuste Basis für produktive Setups
Wenn ich Nginx für produktive DNS-Auflösung aufsetze, halte ich die Konfiguration so schlank wie möglich: feste Ziele in upstream-Gruppen, dynamische Hostnamen nur dort, wo sie wirklich gebraucht werden, ein interner Resolver und ein Cachefenster, das zur Änderungsfrequenz des Backends passt. Das ist weniger spektakulär als ein „alles ist dynamisch“-Ansatz, aber im Betrieb deutlich angenehmer.
- Nur dort dynamisch auflösen, wo sich der Zielhost wirklich zur Laufzeit ändern muss.
- Resolver möglichst intern oder lokal betreiben.
-
validan die tatsächliche Änderungsrate der DNS-Zone anpassen. -
resolver_timeoutkurz halten, damit DNS-Probleme nicht unnötig lange blockieren. - IPv4 und IPv6 bewusst aktivieren oder deaktivieren, statt beides beiläufig zu akzeptieren.
Wenn ich eine Änderung freigebe, teste ich zuerst die Konfiguration mit nginx -t, dann einen gezielten Backendwechsel und anschließend das Verhalten im Log. Genau so sehe ich am schnellsten, ob Nginx die neuen Adressen zur erwarteten Zeit übernimmt und ob die DNS-Schicht wirklich stabil genug ist, um im Alltag nicht zur Fehlerquelle zu werden.