Die Meldung nginx no resolver defined to resolve wirkt oft komplizierter, als sie ist: NGINX soll einen Hostnamen erst zur Laufzeit auflösen, hat dafür aber keinen DNS-Resolver definiert. Ich zeige hier, warum der Fehler in Proxy-, Upstream- und TLS-Szenarien entsteht, wie du ihn sauber behebst und welche Einstellungen in produktiven Setups wirklich sinnvoll sind. Außerdem trenne ich klar zwischen Fällen, in denen ein Resolver nötig ist, und solchen, in denen die Konfiguration auch ohne DNS-Lookup stabil funktioniert.
Die Ursache liegt fast immer in einer DNS-Auflösung zur Laufzeit
- NGINX kann Hostnamen entweder beim Laden der Konfiguration oder erst während einer Anfrage auflösen.
- Der Fehler entsteht meist dann, wenn Variablen, dynamische Upstreams oder OCSP-Abfragen im Spiel sind.
- Die saubere Lösung ist ein resolver im passenden Kontext plus ein sinnvoller Timeout-Wert.
- Ein statischer Backend-Name braucht oft keinen Resolver, ein dynamischer Name dagegen schon.
- Im Produktivbetrieb sind interne DNS-Server und ein bewusst gesetztes Caching meist die robusteste Wahl.
Was die Meldung technisch bedeutet
NGINX unterscheidet streng zwischen statischer und dynamischer Namensauflösung. Wenn ein Hostname bereits beim Einlesen der Konfiguration feststeht, kann NGINX ihn früh auflösen und die Verbindung später direkt aufbauen. Sobald ein Name aber erst während einer Anfrage zusammengesetzt wird, etwa über Variablen, muss NGINX selbst DNS fragen - und genau dafür fehlt dann der Resolver.
Der eigentliche Kern ist also einfach: Nicht jeder Hostname braucht DNS zur Laufzeit. Ein fest definierter Upstream funktioniert anders als ein per Variable zusammengesetzter Zielwert. Ich sehe in der Praxis oft, dass genau dieser Unterschied übersehen wird und dann der falsche Fix gesucht wird.
- statisch bedeutet: Der Zielhost ist fest vorgegeben und kann früh geprüft werden.
- dynamisch bedeutet: Der Zielhost entsteht erst im Request-Kontext und braucht dann DNS.
Damit ist der Unterschied klar. Als Nächstes lohnt sich der Blick auf die typischen Konfigurationen, in denen der Lookup überhaupt erst ausgelöst wird.
Wann NGINX den Resolver wirklich braucht
Die meisten Fälle lassen sich auf ein paar Muster reduzieren. Die NGINX-Dokumentation macht bei proxy_pass mit Variablen genau diesen Mechanismus sichtbar: Wenn der Name erst im Request-Kontext entsteht, muss NGINX ihn über einen Resolver bestimmen. Bei dynamischen Upstreams, OCSP-Abfragen und ähnlichen Funktionen gilt dasselbe Prinzip.
| Szenario | Warum DNS zur Laufzeit nötig ist | Typische Reaktion |
|---|---|---|
proxy_pass http://backend$request_uri; |
Der Zielhost hängt von einer Variable ab. | Resolver in http, server oder location definieren. |
server app.internal.example:8080 resolve; |
IP-Adressen sollen sich ohne Reload aktualisieren. |
zone und resolve verwenden, dazu Resolver setzen. |
ssl_stapling oder ssl_ocsp
|
Der OCSP-Responder muss per Hostname erreicht werden. | DNS-Resolver für den TLS-Kontext hinterlegen. |
statische proxy_pass-Ziele ohne Variablen |
Der Hostname kann früh aufgelöst werden. | Oft kein zusätzlicher Resolver nötig. |
Die praktische Frage ist also nicht, ob NGINX DNS kann, sondern wo genau der Lookup zur Laufzeit ausgelöst wird. Genau dort setzt die Korrektur an.

So behebst du den Fehler sauber
Ich gehe die Behebung in dieser Reihenfolge an: erst den Ort finden, an dem der Hostname dynamisch wird, dann den passenden Resolver eintragen, danach Timeout und Cache-Logik prüfen. Ein bloßes Verschieben der Fehlermeldung ist kein Fix; die Konfiguration muss genau dort ergänzt werden, wo NGINX den Namen wirklich auflöst.
Variante mit proxy_pass und Variablen
Wenn du proxy_pass mit Variablen verwendest, braucht NGINX einen Resolver in demselben Verarbeitungsbereich. Ein typisches Beispiel ist ein Pfad, der an einen internen Service weiterleitet und dabei URI-Teile dynamisch zusammenbaut.
location /api/ {
resolver 10.0.0.53 10.0.0.54 valid=30s;
resolver_timeout 5s;
proxy_pass http://api-backend$request_uri;
}Wichtig ist hier nicht nur der Resolver selbst, sondern auch die erreichbaren DNS-Server. Wenn die Namen nie aufgelöst werden können, hilft die sauberste NGINX-Konfiguration nicht weiter. Ich prüfe deshalb zuerst, ob der DNS-Name außerhalb von NGINX überhaupt antwortet.
Variante mit dynamischen Upstreams
Wenn sich die IP-Adresse eines Backends regelmäßig ändert, ist ein klassischer statischer Upstream oft zu träge. Mit der resolve-Option kann NGINX solche Namen nachziehen, ohne dass ich den Dienst bei jeder Änderung neu laden muss.
upstream app_backend {
zone app_backend 64k;
server app.internal.example:8080 resolve;
}
server {
location / {
proxy_pass http://app_backend;
}
}Der entscheidende Punkt ist die Shared-Memory-Zone. Ohne sie kann NGINX die Laufzeitauflösung nicht sauber verwalten. Genau hier scheitern viele Konfigurationen, weil nur resolve ergänzt wird, der notwendige Rest aber fehlt.
Lesen Sie auch: Nginx Proxy Manager - Einfach Reverse Proxy & SSL verwalten
Variante für OCSP und Stapling
Bei TLS-Funktionen wie OCSP Stapling oder OCSP-Prüfungen ist der Resolver ebenfalls Pflicht, sobald der Responder als Hostname kommt. In solchen Setups trage ich den Resolver meist im http- oder server-Block ein, damit die Zertifikatsprüfung nicht an der DNS-Auflösung hängen bleibt.
server {
ssl_stapling on;
ssl_stapling_verify on;
resolver 10.0.0.53 10.0.0.54 valid=60s;
}Gerade bei Zertifikatsprüfung wird der Fehler leicht übersehen, weil er nicht beim normalen Request-Proxying auftritt, sondern erst beim TLS-Handshake. Das macht die Ursache unsichtbarer, aber nicht komplizierter: Der Hostname muss aufgelöst werden, also braucht NGINX einen Resolver.
Wenn du diese drei Muster kennst, lässt sich der Fehler meist in wenigen Minuten einordnen. Danach geht es nur noch darum, die Werte vernünftig statt nur irgendwie zu setzen.
Welche Resolver-Einstellungen sich in der Praxis bewähren
Ich bevorzuge in produktiven Umgebungen einen internen oder lokal kontrollierten DNS-Server. NGINX empfiehlt für sensible Umgebungen ebenfalls, DNS-Server in einem vertrauenswürdigen lokalen Netz zu betreiben. Das ist meist stabiler und besser kontrollierbar als ein externer Public Resolver, vor allem wenn interne Service-Namen oder private Zonen im Spiel sind.
Der Standard für resolver_timeout liegt bei 30s. In vielen produktiven Umgebungen setze ich bewusst kürzere Werte wie 5s, damit eine DNS-Störung nicht eine ganze Anfragekette blockiert. Das ist kein Dogma, aber ein praktikabler Ausgangspunkt.
| Einstellung | Praktischer Richtwert | Warum das sinnvoll ist |
|---|---|---|
resolver |
1 bis 2 DNS-Server mit klaren IP-Adressen | Redundanz ohne unnötige Komplexität |
valid |
30s bis 300s, bei sehr dynamischen Services auch 5s bis 10s | Kontrolliert, wie lange Antworten zwischengespeichert werden |
resolver_timeout |
2s bis 5s statt des 30s-Defaults | Begrenzt die Wartezeit auf DNS und hält Anfragen reaktionsfähig |
ipv4 / ipv6
|
Nur gezielt abschalten, wenn die Umgebung es verlangt | Verhindert unnötige Fehlversuche auf einer ungenutzten Protokollfamilie |
NGINX cached Antworten standardmäßig nach der Gültigkeit der DNS-Antwort. Mit valid= kannst du das Verhalten bewusst enger oder großzügiger machen. Für häufig wechselnde Backends nehme ich kürzere Werte, für stabile interne Services eher längere. Entscheidend ist, dass die Cache-Dauer zu den Änderungsintervallen deiner Infrastruktur passt.
Ich achte außerdem darauf, dass Resolver und Backends im selben Vertrauensmodell liegen. DNS ist ein kritischer Teil der Kette; wenn dort Wildwuchs herrscht, wird aus einem kleinen Konfigurationsfehler schnell ein schwer reproduzierbares Betriebsproblem. Der nächste Abschnitt zeigt, welche Fehler ich deshalb fast immer doppelt prüfe.
Typische Fehler, die den Fix wieder zunichtemachen
Viele Konfigurationen scheitern nicht an der Idee, sondern an einem Detail. Wenn der erste Fix nicht greift, gehe ich diese Punkte fast immer in genau dieser Reihenfolge durch:
- Der Resolver steht im falschen Kontext oder nicht dort, wo die Variable tatsächlich ausgewertet wird.
-
proxy_passenthält Variablen, aber der Zielhost ist nicht sauber gebildet. - Bei dynamischen Upstreams fehlt die
zone, obwohlresolvegesetzt wurde. - Die DNS-Server sind aus Sicht des NGINX-Hosts nicht erreichbar oder zu langsam.
- Es wird ein interner Name verwendet, aber nur ein externer Resolver ist eingetragen.
- Die Konfiguration wurde geändert, aber NGINX wurde nicht sauber getestet und neu geladen.
Ein häufiger Denkfehler ist außerdem die Annahme, jeder Hostname im Proxy brauche automatisch einen Resolver. Das stimmt nicht. Wenn der Name statisch ist und NGINX ihn beim Laden der Konfiguration auflösen kann, ist kein zusätzlicher DNS-Schritt nötig. Der Fehler taucht erst auf, wenn die Auflösung bewusst in die Laufzeit verschoben wird.
Ein sauberer Fix endet aber nicht bei der Syntax. Im Betrieb zählen noch ein paar zusätzliche Kontrollen.
Was ich in produktiven Setups zusätzlich absichere
Wenn ich eine NGINX-Konfiguration mit dynamischer Namensauflösung prüfe, schaue ich nicht nur auf den einen Fehler, sondern auf die gesamte Kette. Das verhindert, dass der schnelle Fix später zu Latenzen, fehlerhaften Fallbacks oder unnötigen Ausfällen führt.
-
nginx -tvor dem Reload - so fallen Syntaxfehler sofort auf. -
Erreichbarkeit des DNS - ein kurzer Test mit
digodernslookupvom NGINX-Server aus zeigt, ob der Resolver wirklich antwortet. - Trennung von intern und extern - interne Ziele sollten auch über interne DNS-Zonen aufgelöst werden.
- Timeouts beobachten - wenn DNS langsam wird, wirkt das direkt auf die Latenz der Requests.
- Logs prüfen - der Error-Log zeigt oft präziser als die oberflächliche Meldung, wo die Auflösung scheitert.
In Container-Umgebungen liegt die Ursache oft im Netzpfad zum DNS und nicht in der NGINX-Datei selbst. Gerade dort zahlt sich ein klarer Resolver pro Umgebung aus, statt eine generische Standardannahme zu verwenden. Wer an dieser Stelle sauber arbeitet, spart sich später viel Fehlersuche.
Wenn diese Kontrollen sitzen, ist der Fehler nicht nur beseitigt, sondern auch verstanden. Genau das ist die Basis für eine belastbare Konfiguration.
Was dieser Fehler über deine Konfiguration verrät
Der eigentliche Wert dieser Meldung liegt nicht nur im Fix, sondern in der Diagnose. Sie zeigt dir, dass deine Konfiguration an einer Stelle dynamisch geworden ist, an der NGINX vorher statisch gearbeitet hat. Genau dort lohnt sich ein sauberer Blick auf Variablen, DNS-Zonen und die Frage, ob ein Hostname wirklich zur Laufzeit entstehen muss.
- Statische Ziele brauchen meist keinen zusätzlichen Resolver.
- Dynamische Ziele brauchen einen Resolver im passenden Kontext.
-
resolvegehört bei wechselnden Upstreams fast immer mit dazu. - Kurze Timeouts und nachvollziehbares DNS sind im Betrieb oft robuster als Standardwerte.
Wenn du den Fehler so behandelst, löst du nicht nur die aktuelle Störung, sondern machst die NGINX-Konfiguration insgesamt belastbarer. Das ist genau der Punkt, an dem ein kleiner DNS-Hinweis in der Praxis zu einer deutlich stabileren Webserver-Architektur führt.