Die wichtigsten Punkte auf einen Blick
- 502 heißt: NPM hat die Anfrage angenommen, aber vom Zielsystem keine gültige Antwort bekommen.
- Die häufigsten Ursachen sind ein falscher Host oder Port, ein HTTP/HTTPS-Mismatch, ein kaputtes Docker-Netzwerk oder ein nicht laufender Backend-Dienst.
- Wenn nur einzelne Apps ausfallen, sind oft Header, Cookies oder Buffergrößen das eigentliche Problem.
- Wenn sogar die NPM-Oberfläche 502 zeigt, liegt der Fehler oft im eigenen Stack, etwa bei Datenbank, Volume oder Containerstart.
- Die schnellste Diagnose läuft über die NPM-Logs und einen direkten Verbindungscheck aus dem Proxy-Container.
Was der Fehler im Proxy-Setup wirklich bedeutet
Ein 502 entsteht an der Übergabestelle zwischen Nginx Proxy Manager und dem dahinterliegenden Dienst. Der Proxy funktioniert also nicht deshalb falsch, weil der Browser etwas „kaputt“ macht, sondern weil der Upstream keine brauchbare Antwort liefert. Das ist ein wichtiger Unterschied, denn damit grenzt man die Fehlersuche sofort ein: Das Problem liegt entweder im Zielsystem selbst oder auf dem Weg dorthin.
Die offizielle NGINX-Dokumentation beschreibt 502 unter anderem dann, wenn ein Upstream nicht rechtzeitig ausgewählt oder erreicht werden kann. In der Praxis sehe ich genau diese drei Klassen sehr oft: Verbindung klappt nicht, Antwort ist syntaktisch oder technisch unbrauchbar, oder der Zielserver ist zwar da, reagiert aber zu langsam.
| Status | Was er meist bedeutet | Worauf ich zuerst schaue |
|---|---|---|
| 502 Bad Gateway | Proxy bekommt keine gültige Antwort vom Upstream | Host, Port, Protokoll, Netzwerk, TLS, Header |
| 504 Gateway Timeout | Upstream antwortet zu langsam | Performance, Timeouts, Last, DB, Backend-Start |
| 404 Not Found | Upstream ist erreichbar, aber der Pfad stimmt nicht | Routing, Pfad, App-Konfiguration |
Diese Unterscheidung spart Zeit. Wenn ich 502 und 504 sauber trenne, fallen viele falsche Vermutungen sofort weg. Als Nächstes lohnt sich deshalb der direkte Gesundheitscheck zwischen NPM und Zielsystem.

Die schnellste Diagnose im laufenden Betrieb
Mein erster Griff ist fast immer die Fehlerdatei des Proxys. Im Nginx-Proxy-Manager-Repository wird für 502-Fehler auf /data/logs/error.log verwiesen, und genau dort stehen oft die entscheidenden Hinweise: Connection refused, handshake failed, upstream timed out oder upstream sent too big header. Ohne diese Zeilen stochert man schnell im Nebel.
- Ich öffne die Proxy-Logs und prüfe die genaue Fehlermeldung zur Uhrzeit des Fehlers.
- Ich teste den Upstream direkt aus dem NPM-Container heraus, nicht nur vom Host.
- Ich nutze dieselbe Kombination aus Schema, Host und Port, die auch NPM verwendet.
- Ich vergleiche, ob der Fehler nur bei einem Host, nur bei einem Pfad oder nur nach einem Redeploy auftritt.
- Ich schaue parallel in die Logs des Zielcontainers oder der Zielanwendung.
docker exec -it nginx-proxy-manager sh
curl -I http://backend:8080
curl -I https://backend:8443
Wenn der erste Aufruf funktioniert, der zweite aber nicht, ist das schon ein sehr guter Hinweis auf ein Protokollproblem. Wenn beide fehlschlagen, ist die Verbindung selbst kaputt, der Dienst läuft nicht oder der Zielport stimmt nicht. Wenn der Aufruf nur aus dem Host klappt, aber nicht aus dem Container, ist fast immer das Netzwerk der eigentliche Fehlerpunkt.
Mit diesem Schnelltest bin ich meist schon in der richtigen Fehlerklasse. Danach geht es an die typischen Ursachen, die in der Realität den Großteil der Fälle ausmachen.
Die häufigsten Ursachen in der Praxis
Ich sortiere die meisten Fälle in einer recht kleinen Menge an Ursachen. Das ist angenehm unspektakulär, aber genau deshalb so nützlich: In produktiven Umgebungen sind es selten exotische Spezialfälle, sondern immer wieder dieselben Konfigurationsfehler oder Betriebsprobleme.
| Symptom | Wahrscheinliche Ursache | Konkreter Gegencheck |
|---|---|---|
| 502 sofort nach dem Aufruf | Falscher Host oder Port | Stimmt der Zielport wirklich mit dem lauschenenden Dienst überein? |
| 502 nur bei HTTPS | HTTP/HTTPS vertauscht oder TLS-Handshake schlägt fehl | Spricht der Backend-Dienst wirklich TLS auf diesem Port? |
| 502 nach Container-Neustart | Veraltete Zieladresse oder Netzwerkproblem | Wurde der Proxy-Host neu geladen, und ist der Dienstname stabil? |
| 502 nur bei Login oder Upload | Zu kleine Buffer oder große Header | Sind Cookies, Tokens oder Antwort-Header ungewöhnlich groß? |
| 502 nach einigen Sekunden | Timeout oder überlasteter Upstream | Ist das Backend langsam, blockiert oder noch im Startvorgang? |
Ein klassischer Anfängerfehler ist übrigens die Annahme, dass ein erreichbares Zielsystem automatisch ein korrekt erreichbares Zielsystem ist. Ein Dienst kann auf dem Host per Browser funktionieren und trotzdem aus dem NPM-Container heraus scheitern, weil Netzwerke, Firewall oder Docker-DNS anders greifen. Genau deshalb prüfe ich immer aus derselben Perspektive, aus der NPM später auch arbeitet.
Ein zweiter Dauerbrenner ist die Verwechslung von Protokoll und Port. Wenn ein Backend auf 8080 reines HTTP spricht, aber NPM per HTTPS darauf zugreifen soll, sieht man oft TLS-Fehler oder eine generische 502-Meldung. Das wirkt im ersten Moment wie ein Proxy-Problem, ist aber in Wirklichkeit nur ein falsch beschriebener Upstream.
Ein dritter Punkt, den ich nie unterschätze, ist die Startreihenfolge. Wenn NPM schneller hochkommt als die Anwendung dahinter, kann der erste Request ins Leere laufen. Bei ungeduldigen Setups ist ein Healthcheck oft wertvoller als ein weiterer manueller Neustart. Damit ist die Ursache meist schon deutlich enger gefasst. Der nächste Stolperstein sitzt oft im Docker- und DNS-Teil der Kette.
Docker und DNS als versteckte Fehlerquelle
In Container-Umgebungen ist die schönste Ursache oft auch die trügerischste: Der Upstream hat eine IP, aber nicht zwingend die richtige IP. Wenn ich in NPM mit festen Adressen arbeite, kann ein erneuter Containerstart den Zielserver an eine neue Adresse hängen. Für den Browser ist das unsichtbar, für den Proxy aber fatal.
Ein aktueller Fall im Nginx-Proxy-Manager-Repository beschreibt genau dieses Muster: Nach dem Neuerstellen eines Backend-Containers behielt eine Custom Location die alte Upstream-IP und lieferte weiter 502, bis der Proxy-Host erneut gespeichert wurde. Das ist kein theoretischer Sonderfall, sondern ein echtes Betriebsrisiko bei dynamischen Container-Deployments.
Mein praktischer Ansatz ist deshalb ziemlich klar:
- Ich bevorzuge stabile Service-Namen innerhalb desselben Docker-Netzwerks statt manuell gepflegter Container-IPs.
- Ich prüfe, ob NPM und Backend wirklich im gleichen benutzerdefinierten Bridge-Netz hängen.
- Ich vermeide Mischformen aus Host-IP, Router-DNS und Container-Namen, wenn ein einfacher interner Name reicht.
- Nach Redeploys teste ich gezielt die betroffenen Pfade erneut, nicht nur die Startseite.
Wichtig ist auch der Unterschied zwischen Hauptpfad und Custom Location. Manchmal funktioniert die Haupt-Route noch, während ein Unterpfad bereits 502 liefert. Das ist ein starkes Indiz dafür, dass nur ein Teil der Konfiguration veraltet ist und nicht der ganze Stack.
Wenn das Netzwerk sauber ist und die Namen stabil sind, bleiben oft nur noch die Protokoll- und Response-Ebene. Genau dort wird der Fehler dann technischer, aber auch eindeutiger.
SSL, Header und Timeouts sauber einordnen
Ein 502 kann auch dann auftauchen, wenn die Verbindung an sich existiert, aber die Antwort für Nginx nicht verwertbar ist. Das passiert zum Beispiel bei TLS-Handshakes, bei großen Headern oder bei sehr trägen Antworten. Gerade bei modernen Web-Apps mit SSO, vielen Cookies oder langen Redirect-Ketten sehe ich das deutlich öfter als viele erwarten.
Die NGINX-Standardeinstellungen sind hier eher konservativ. proxy_buffer_size liegt standardmäßig bei 4k oder 8k, proxy_read_timeout bei 60s, ebenso proxy_connect_timeout und proxy_send_timeout. Das ist für viele Anwendungen völlig ausreichend, aber nicht für jede. Wenn eine App große Cookies oder umfangreiche Antwort-Header erzeugt, kann der Proxy die Antwort als ungültig behandeln.
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_busy_buffers_size 32k;
Solche Werte nutze ich als pragmatischen Ausgangspunkt, nicht als Dogma. Sie helfen vor allem dann, wenn Login-Flows, SSO-Weiterleitungen oder sehr große Session-Header das Problem auslösen. Wenn die App dagegen schlicht zu langsam ist, bringen größere Buffer nichts. Dann muss ich an die Arbeitslast, Datenbank, Caches oder den Startprozess des Backend-Dienstes.
Bei HTTPS zum Upstream gilt für mich noch eine einfache Regel: Wenn das Log eine Zeile wie ein TLS- oder Handshake-Problem andeutet, prüfe ich zuerst das Protokoll und erst danach Zertifikatsdetails. Interne Zertifikate, falsche Ports oder ein Dienst, der gar kein TLS spricht, erzeugen sehr ähnliche Symptome. Mit dem Auge auf die Logzeile lässt sich das meist schnell trennen.
Wenn diese Ebene sauber ist, sind viele 502-Fälle schon erledigt. Bleibt noch der Sonderfall, dass nicht ein Proxy-Host, sondern die NPM-Oberfläche selbst ausfällt.
Wenn die NPM-Oberfläche selbst ausfällt
Zeigt schon die Verwaltungsoberfläche von Nginx Proxy Manager 502, dann suche ich den Fehler nicht in einem einzelnen Proxy-Host. Dann ist meist der eigene Stack betroffen: Datenbank, Containerstart, Volume, Berechtigungen oder ein beschädigter Konfigurationszustand. In dieser Lage bringt es wenig, an der Weiterleitung eines einzelnen Domains zu schrauben.
In solchen Fällen prüfe ich zuerst, ob die Container überhaupt sauber laufen und ob die Datenbank erreichbar ist. Ein Restart-Loop des DB-Containers, ein volles Volume oder eine beschädigte Konfigurationsdatei kann den ganzen Dienst blockieren. Das sieht im Browser wie ein simples Gateway-Problem aus, ist technisch aber ein Systemfehler im NPM-Stack.
Meine Reihenfolge ist dann bewusst nüchtern:
- Containerstatus prüfen statt an Proxy-Hosts zu drehen.
- Logs lesen, bevor ich neu deploye.
- Datenbank und Speicher prüfen, wenn die UI nicht lädt.
- Volumes und Berechtigungen kontrollieren, wenn der Fehler nach einem Update auftritt.
Der entscheidende Punkt ist hier die Disziplin: Erst die Plattform gesund machen, dann die Anwendung darauf. Wer diese Reihenfolge umdreht, verliert Zeit und verändert am Ende oft die falsche Stelle. Damit ist die letzte Etappe der Diagnose klar: Wie verhindere ich, dass derselbe Fehler nach dem Fix direkt wiederkommt?
So verhindere ich die nächste Störung beim nächsten Deploy
Nach dem eigentlichen Fix denke ich immer an Stabilität. Ein Proxy ist nur dann wirklich gut, wenn er auch bei Redeploys, kurzen Ausfällen und Änderungen im Backend sauber weiterarbeitet. Dafür reichen meist einige wenige, aber konsequent umgesetzte Regeln.
- Ich setze interne Service-Namen statt wackeliger IPs.
- Ich halte Backend und NPM im gleichen Docker-Netzwerk.
- Ich teste nach Updates einmal gezielt den Pfad, der vorher gestört war.
- Ich werte Logs nicht nur im Fehlerfall aus, sondern auch bei ungewöhnlichen Deployments.
- Ich ändere Custom Configs nur dann, wenn ich den Effekt auf Header, Buffer und TLS wirklich verstehe.