nginx 502 Bad Gateway beheben: Ursachen und Lösungen

Veröffentlicht am 15 Min. Lesezeit

502 Bad Gateway heißt: nginx hat vom Backend keine gültige Antwort bekommen. Die fünf häufigsten Ursachen, die passende Zeile im Fehlerprotokoll und wie Sie belegen, dass der Fix wirklich greift.

Was "502 Bad Gateway" wirklich bedeutet

Ein 502 kommt nicht von Ihrer Anwendung, er kommt von nginx. nginx hat die Anfrage angenommen, an ein Backend weitergereicht (PHP-FPM, Node, Python, ein anderer Webserver) und von dort keine verwertbare Antwort bekommen. Deshalb steht auf der Fehlerseite nichts Brauchbares.

Die Abgrenzung zu den Nachbarcodes spart im Ernstfall viel Zeit:

  • 500 Internal Server Error: das Backend hat geantwortet, die Antwort war ein Fehler. Ursache liegt im Anwendungscode. Log der Anwendung lesen, nicht das von nginx.
  • 502 Bad Gateway: Verbindung zum Backend kam nicht zustande oder brach ab, bevor eine vollständige Antwort da war.
  • 504 Gateway Time-out: Verbindung stand, das Backend hat nur zu lange geschwiegen, und nginx hat die Geduld verloren.

Diese Unterscheidung ist der wichtigste Hebel bei Zeitüberschreitungen, weil dieselbe langsame Seite je nachdem, wer zuerst abbricht, einmal als 502 und einmal als 504 erscheint. Dazu weiter unten mehr.

Die Paketlage auf Debian 13, Debian 12, Ubuntu 24.04 und Ubuntu 22.04

nginx verhält sich bei 502-Fehlern auf allen vier Systemen gleich, die Direktiven heißen identisch. Die Unterschiede stecken fast vollständig auf der PHP-Seite, und genau daraus entstehen die meisten 502er nach einem Distributionswechsel.

SystemnginxPHPDienstnameSocket
Debian 13 (Trixie)1.26.38.4php8.4-fpm/run/php/php8.4-fpm.sock
Debian 12 (Bookworm)1.22.18.2php8.2-fpm/run/php/php8.2-fpm.sock
Ubuntu 24.04 LTS1.24.08.3php8.3-fpm/run/php/php8.3-fpm.sock
Ubuntu 22.04 LTS1.18.08.1php8.1-fpm/run/php/php8.1-fpm.sock

Ersetzen Sie in allen folgenden Befehlen die Versionsnummer durch die Ihres Systems. Alle Beispiele gehen von einer root-Shell aus, sonst sudo davorsetzen. Welche Version installiert ist, verrät ein Blick auf die FPM-Binärdateien, auch wenn der Dienst gar nicht startet:

ls /usr/sbin/php-fpm*
ls /etc/php/

Zuerst das Fehlerprotokoll: die richtige Zeile finden

Der häufigste Fehler bei der Diagnose ist, im falschen Protokoll zu suchen. nginx hat ein globales Fehlerprotokoll und pro virtuellem Host oft ein eigenes. Welche Datei gilt, steht in der Konfiguration:

grep -Rn "error_log" /etc/nginx/nginx.conf /etc/nginx/sites-enabled/

Achten Sie auf das große -R. In /etc/nginx/sites-enabled/ liegen auf Debian und Ubuntu ausschließlich Symlinks nach sites-available, und GNU grep folgt mit dem kleinen -r beim rekursiven Abstieg keinem Symlink. Mit -rn bekommen Sie deshalb nur die Treffer aus nginx.conf, während die vhost-eigene error_log-Zeile unsichtbar bleibt: genau die, die im 502-Fall gesucht ist, weil der globale Log den FastCGI-Fehler nicht enthält, sobald der vhost umleitet. Wer lieber bei -r bleibt, greppt die Quellverzeichnisse direkt:

grep -rn "error_log" /etc/nginx/nginx.conf /etc/nginx/sites-available/ /etc/nginx/conf.d/

Ohne eigene Angabe im Server-Block landet alles in /var/log/nginx/error.log. Der zuverlässigste Weg zur passenden Zeile führt über einen Live-Mitschnitt: Protokoll in einem Terminal offen halten, im zweiten die Anfrage auslösen, und die Zeilen ansehen, die dabei neu dazukommen.

tail -f /var/log/nginx/error.log

Alternativ auf den Zeitstempel filtern. nginx schreibt lokale Zeit im Format 2026/07/26 09:14:22, nicht in UTC. Ein Abgleich mit einer Uhr in anderer Zeitzone geht regelmäßig schief.

Eine 502-Zeile ist immer nach demselben Muster aufgebaut. Beispiel:

2026/07/26 09:14:22 [error] 812#812: *3 connect() to unix:/run/php/php8.2-fpm.sock
failed (2: No such file or directory) while connecting to upstream,
client: 203.0.113.7, server: example.com,
request: "GET /index.php HTTP/1.1",
upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:", host: "example.com"

Vier Bestandteile tragen die gesamte Information:

  1. Der Systemaufruf: connect(), recv(), send(). connect() heißt, es kam nie eine Verbindung zustande. recv() heißt, die Verbindung stand und brach dann ab.
  2. Die Fehlernummer in Klammern, siehe Tabelle unten. Das ist die eigentliche Diagnose.
  3. Die Phase: while connecting to upstream gegenüber while reading response header from upstream. Ersteres ist ein Erreichbarkeits-, letzteres ein Laufzeit- oder Absturzproblem.
  4. Das Feld upstream:. Dort steht der Pfad oder die Adresse, die nginx wirklich benutzt hat. Nicht das, was Sie in der Konfiguration vermuten, sondern das, was aktiv geladen ist.
MeldungBedeutungAbschnitt
2: No such file or directorySocket-Datei existiert nichtDienst tot oder Pfad falsch
13: Permission deniedSocket existiert, nginx darf nicht darauf zugreifenRechte
111: Connection refusedNichts lauscht auf Adresse und PortBackend nicht erreichbar
110: Connection timed outKeine Antwort in der FristZeitüberschreitung
104: Connection reset by peerBackend-Prozess ist mitten in der Anfrage gestorbenAbstürze und Limits
11: Resource temporarily unavailableWarteschlange des Sockets vollAbstürze und Limits

Die Zeile zu 13: Permission denied trägt bei nginx häufig die Stufe [crit] statt [error]. Wer nur nach [error] filtert, übersieht sie. Filtern Sie besser auf den Text:

grep -n "upstream" /var/log/nginx/error.log

Die zweite Hälfte der Wahrheit steht im Protokoll von PHP-FPM, standardmäßig unter /var/log/php8.2-fpm.log. Bei Abstürzen und Limits steht dort die Begründung, während nginx nur das Symptom sieht.

Ursache 1: PHP-FPM läuft nicht

Klassische Fehlernummer 2. Prüfen Sie zuerst den Zustand des Dienstes:

systemctl is-active php8.2-fpm
systemctl status php8.2-fpm --no-pager -l

is-active antwortet mit einem Wort, das genügt für ein Skript. Kommt inactive oder failed, holen Sie den Grund aus dem Journal, und zwar mit Zeitfenster statt der letzten zehn Zeilen:

journalctl -u php8.2-fpm --since "30 min ago" --no-pager

Sehr oft ist die Ursache eine kaputte Pool-Konfiguration, die nach einem Reload liegen blieb. FPM hat einen eigenen Syntaxtest, der ohne Neustart läuft:

php-fpm8.2 -t

Typische Startfehler im Wortlaut und was sie heißen:

  • ERROR: [pool www] cannot get uid for user 'webuser': der in user = eingetragene Systembenutzer existiert nicht mehr, etwa nach einer Migration.
  • ERROR: unable to bind listening socket for address '/run/php/php8.2-fpm.sock': No such file or directory (2): das Verzeichnis /run/php fehlt. Es liegt auf einem tmpfs und wird beim Start des Dienstes angelegt. Wer listen auf einen Pfad außerhalb zeigen lässt, muss das Verzeichnis selbst anlegen lassen.
  • ERROR: An another FPM instance seems to already listen on ...: ein Prozess aus einem missglückten Neustart hängt noch am Socket.

Woran Sie erkennen, dass es wirklich gelöst ist: nicht daran, dass systemctl restart ohne Ausgabe durchlief. Ein FPM-Master startet auch dann, wenn kein einziger Arbeitsprozess Anfragen annehmen kann. Aussagekräftig ist, dass der Socket im System sichtbar ist und dass FPM darauf antwortet.

ss -lx | grep php

Für den echten Antworttest aktivieren Sie in /etc/php/8.2/fpm/pool.d/www.conf die Zeile ping.path = /ping, laden FPM neu und fragen den Socket direkt an, vollständig an nginx vorbei:

apt-get install -y libfcgi-bin
SCRIPT_NAME=/ping SCRIPT_FILENAME=/ping REQUEST_METHOD=GET \
  cgi-fcgi -bind -connect /run/php/php8.2-fpm.sock

Kommt pong zurück, ist die PHP-Seite in Ordnung und der Fehler liegt zwischen nginx und dem Socket. Kommt nichts zurück, brauchen Sie an nginx gar nicht weiterzusuchen.

Ursache 2: falscher Socket-Pfad

Das ist auf Debian und Ubuntu die mit Abstand häufigste Ursache, weil der Socket den PHP-Versionsnamen trägt, die nginx-Konfiguration diesen Namen fest verdrahtet, und ein Distributionsupgrade beides auseinanderreißt.

Konkret: Ein Upgrade von Debian 12 auf Debian 13 hebt PHP von 8.2 auf 8.4. Der alte Socket /run/php/php8.2-fpm.sock verschwindet, in der vhost-Datei steht er weiter. Ergebnis ist ein 502 auf jeder einzelnen PHP-Seite, sofort nach dem Neustart. Dasselbe passiert bei Ubuntu 22.04 auf 24.04 (8.1 auf 8.3).

Eine zweite Falle steckt in der mitgelieferten Beispielkonfiguration. In /etc/nginx/sites-available/default steht ein auskommentierter Block, dessen fastcgi_pass auf eine PHP-Version zeigt, die seit Jahren nicht mehr aktuell ist. Wer diese Zeilen nur entkommentiert, hat den 502 damit erst erzeugt.

Vergleichen Sie beide Seiten. Was nginx benutzen will:

grep -Rn "fastcgi_pass" /etc/nginx/

Was FPM tatsächlich anbietet:

grep -n "^listen *=" /etc/php/*/fpm/pool.d/*.conf

Der Zusatz *= im Suchmuster ist Absicht, er verlangt hinter listen beliebig viele Leerzeichen und dann ein Gleichheitszeichen. Ein bloßes ^listen trifft nämlich auch listen.owner, listen.group und listen.mode, und die gesuchte Zeile geht zwischen den Treffern unter. Der Platzhalter /etc/php/*/ ist dagegen richtig so, er deckt jede installierte PHP-Version ab. Und was im laufenden System existiert:

ls -l /run/php/

Die drei Ausgaben müssen denselben Pfad zeigen. Wichtig: grep -R über /etc/nginx/ statt nur über die eine Datei, die Sie im Verdacht haben. Über include eingebundene Schnipsel sind ein beliebtes Versteck, ebenso alte Dateien in sites-available, die noch über einen vergessenen Symlink in sites-enabled aktiv sind. Auch hier gilt: nur das große -R folgt diesen Symlinks und zeigt Ihnen damit, welche Datei wirklich aktiv ist.

ls -l /etc/nginx/sites-enabled/

Bevor Sie etwas ändern, legen Sie eine Kopie an. Das kostet zwei Sekunden und erspart im Zweifel eine Wiederherstellung aus dem Backup:

mkdir -p /root/backups
cp -a /etc/nginx/sites-available/default /root/backups/default.bak

Wer mehrfach eingreift, hängt besser einen Zeitstempel an (default.bak.$(date +%F-%H%M)), denn cp -a überschreibt eine vorhandene .bak kommentarlos.

Nach der Korrektur immer erst testen, dann laden. reload statt restart, damit bestehende Verbindungen nicht abreißen:

nginx -t
systemctl reload nginx

Beachten Sie: nginx -t prüft ausschließlich die Syntax. Ein Socket-Pfad, den es nicht gibt, gilt als völlig gültige Konfiguration. Ein grünes syntax is ok ist deshalb kein Beleg dafür, dass der 502 weg ist.

Ursache 3: Rechte am Socket

Fehlernummer 13. Der Socket ist da, nginx darf ihn nur nicht öffnen. nginx läuft auf Debian und Ubuntu als Benutzer www-data, und der Standardpool von FPM legt den Socket passend dazu an. Sichtbar wird das in der Pool-Datei:

grep -n "listen.owner\|listen.group\|listen.mode" /etc/php/*/fpm/pool.d/*.conf

Mit listen.owner = www-data, listen.group = www-data und Modus 0660 funktioniert das Zusammenspiel ohne Zutun. Schiefgehen kann es in drei Situationen:

  • Eigener Pool pro Projekt. Wird user und group auf einen Projektbenutzer gesetzt, muss listen.group trotzdem eine Gruppe sein, in der nginx ist. Üblich ist listen.owner = projektuser zusammen mit listen.group = www-data.
  • Socket außerhalb von /run. Nicht nur die Socket-Datei muss zugänglich sein, sondern jedes Verzeichnis auf dem Weg dorthin braucht das Ausführungsrecht für nginx. Ein Socket in einem Heimatverzeichnis mit Modus 0700 ist erreichbar für niemanden außer dem Eigentümer.
  • nginx mit geändertem user in /etc/nginx/nginx.conf.

Den Verdacht bestätigen Sie, ohne zu raten, indem Sie den Zugriff genau als der Benutzer versuchen, der ihn im Betrieb braucht:

id www-data
sudo -u www-data test -w /run/php/php8.2-fpm.sock && echo "Zugriff vorhanden" || echo "kein Zugriff"

Noch aussagekräftiger ist der cgi-fcgi-Aufruf aus dem vorigen Abschnitt, ebenfalls mit sudo -u www-data davor. Antwortet FPM als root, aber nicht als www-data, ist die Diagnose eindeutig.

Setzen Sie die Werte in der Pool-Datei, nicht mit chmod auf der Socket-Datei. Ein chmod 666 hält genau bis zum nächsten Neustart von FPM, dann legt FPM den Socket mit den konfigurierten Rechten neu an, und der Fehler ist zurück, meist zum ungünstigsten Zeitpunkt.

Auf Debian und Ubuntu ist AppArmor aktiv. Ein mitgeliefertes Profil für nginx wird im Auslieferungszustand nicht erzwungen, kann aber durch Härtungsvorlagen scharf geschaltet worden sein. Bleibt eine 13er-Meldung trotz korrekter Rechte bestehen, lohnt der Blick in aa-status und in journalctl -k | grep DENIED.

Ursache 4: Zeitüberschreitung bei langen Anfragen

Hier trennt sich sauberes Vorgehen von Rätselraten, denn ein reiner Ablauf der nginx-Frist erzeugt einen 504, keinen 502. Wenn eine lange Anfrage als 502 endet, hat fast immer PHP-FPM den Arbeitsprozess vorher abgeräumt, und nginx sah nur noch eine abgerissene Verbindung. Im Protokoll steht dann typischerweise:

recv() failed (104: Connection reset by peer) while reading response header from upstream

Drei Fristen wirken gleichzeitig, und ihre Reihenfolge entscheidet über den Statuscode:

  1. max_execution_time in php.ini, Standard 30 Sekunden im FPM-Betrieb. Zählt nur die Laufzeit des Skripts. Wartezeit in Systemaufrufen, etwa auf eine hängende Datenbankabfrage, zählt unter Linux nicht mit. Deshalb rettet dieser Wert bei genau dem Problem nicht, bei dem man ihn erwartet.
  2. request_terminate_timeout in der Pool-Datei, im Auslieferungszustand aus. Beendet den Arbeitsprozess hart, egal woran er hängt. Das ist der Wert, der 502er produziert.
  3. fastcgi_read_timeout in nginx, Standard 60 Sekunden. Läuft er ab, gibt es 504.

Die brauchbare Reihenfolge ist von innen nach außen aufsteigend, damit immer die Schicht zuerst greift, die noch eine verständliche Fehlermeldung erzeugen kann. Zum Beispiel 60, dann 75, dann 90 Sekunden. Umgekehrt sortiert bekommen Sie 502er statt lesbarer PHP-Fehler.

grep -rn "request_terminate_timeout" /etc/php/*/fpm/pool.d/*.conf

Was FPM abgeräumt hat, steht in dessen Protokoll im Klartext:

WARNING: [pool www] child 1234, script '/var/www/html/import.php'
(request: "POST /import.php") execution timed out (76.271849 sec), terminating

Bevor Sie Fristen hochsetzen, lassen Sie sich zeigen, wo die Zeit hingeht. FPM bringt dafür ein eigenes Protokoll mit, das bei Überschreitung einen vollständigen PHP-Aufrufstapel schreibt. In der Pool-Datei aktivieren:

slowlog = /var/log/php-fpm-slow.log
request_slowlog_timeout = 5s

Nach einem systemctl reload php8.2-fpm steht dort bei der nächsten langsamen Anfrage die Funktion samt Zeilennummer, die hängt. In der Praxis ist das in vier von fünf Fällen eine Datenbankabfrage ohne Index oder ein Aufruf an eine fremde Programmierschnittstelle ohne eigene Frist. Fristen hochzudrehen verlängert dann nur die Zeit bis zum Fehler und blockiert zusätzlich Arbeitsprozesse.

Ursache 5: Backend nicht erreichbar

Betrifft jedes Backend, das über TCP angesprochen wird: FPM auf Port 9000, eine Node-Anwendung, ein Java-Dienst, ein Container. Leitmeldung ist Fehlernummer 111.

connect() to 127.0.0.1:3000 failed (111: Connection refused) while connecting to upstream

Prüfen Sie zuerst, ob überhaupt etwas lauscht, und vor allem worauf:

ss -ltnp

Dieser Befehl listet ausschließlich TCP-Sockets, und daraus entsteht ein verbreiteter Trugschluss: ein PHP-FPM-Pool im Auslieferungszustand lauscht auf einem Unix-Socket unter /run/php/ und erscheint in dieser Liste überhaupt nicht, obwohl er einwandfrei läuft. Sichtbar wird er erst so:

ss -lxn | grep php-fpm
ls -l /run/php/

Für FPM ist ss -ltnp also nur dann aussagekräftig, wenn der Pool per listen = 127.0.0.1:9000 bewusst auf TCP umgestellt wurde. Bei Node-, Java- oder Container-Backends ist es dagegen genau der richtige Befehl.

Drei Stolperstellen, die in Anleitungen selten stehen:

  • localhost löst zuerst auf ::1 auf. Steht in nginx proxy_pass http://localhost:3000;, die Anwendung lauscht aber nur auf 127.0.0.1, versucht nginx die IPv6-Adresse und bekommt "Connection refused". Der Dienst läuft, der Port ist offen, trotzdem 502. Lösung: in nginx 127.0.0.1 ausschreiben, oder die Anwendung auf beide Adressfamilien binden.
  • nginx löst Namen einmalig beim Laden auf. Steht im proxy_pass ein Rechnername, merkt nginx sich die Adresse. Wechselt das Backend die IP-Adresse, etwa ein neu gestarteter Container, laufen die Anfragen bis zum nächsten reload in den Leerlauf.
  • Firewall auf dem Rückweg. Bei einem Backend auf einem anderen Server erscheint 113: No route to host oder eine Zeitüberschreitung statt "Connection refused". Prüfen mit ufw status und einem direkten Verbindungstest vom nginx-Server aus.

Wird ein upstream-Block mit mehreren Zielen benutzt, kommt eine eigene Meldung dazu:

no live upstreams while connecting to upstream

Das heißt, nginx hat alle Ziele nach wiederholten Fehlversuchen für fail_timeout aus dem Verkehr genommen. Auch nach der Reparatur des Backends dauert es dann noch bis zum Ablauf dieser Frist, bis wieder Anfragen durchgehen. Ein systemctl reload nginx setzt den Zustand sofort zurück.

Der 502, der zu keiner der fünf Ursachen passt

Zwei Fälle sehen aus wie ein Ausfall, sind aber keiner, und kosten deshalb überdurchschnittlich viel Zeit.

Antwortkopf zu groß. Die Anwendung läuft einwandfrei, nur einzelne Anfragen liefern 502:

upstream sent too big header while reading response header from upstream

Auslöser sind große Cookies oder Sitzungsmerkmale in Kopfzeilen, der Puffer von nginx ist zu klein. Im Server- oder Location-Block:

fastcgi_buffer_size 32k;
fastcgi_buffers 8 16k;
fastcgi_busy_buffers_size 64k;

Bei proxy_pass heißen die Direktiven proxy_buffer_size und proxy_buffers. Typisch ist, dass nur angemeldete Nutzer betroffen sind, während die Startseite tadellos lädt.

Arbeitsprozesse ausgegangen. Unter Last erscheint im FPM-Protokoll:

WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

Neue Anfragen warten dann in der Warteschlange des Sockets. Ist auch die voll, meldet nginx 11: Resource temporarily unavailable. Bevor Sie pm.max_children erhöhen, rechnen Sie kurz nach: verfügbarer Arbeitsspeicher geteilt durch den tatsächlichen Verbrauch eines Arbeitsprozesses. Ein zu hoher Wert tauscht 502er gegen einen Systemzustand ein, in dem der Speicher ausgeht, und das trifft dann auch die Datenbank.

Abstürze. Zeilen mit exited on signal 11 (SIGSEGV) deuten auf eine defekte PHP-Erweiterung hin, häufig nach einem PHP-Versionswechsel mit übrig gebliebenen Modulen aus der Vorversion.

Wenn der Eingriff nichts bringt: der Rückweg

Zwei Regeln halten den Schaden klein. Erstens: eine Änderung nach der anderen, mit Kopie der Originaldatei unter /root/backups, niemals im Web-Verzeichnis. Zweitens: nach jedem Schritt gegenprüfen, statt drei Dinge gleichzeitig zu ändern und anschließend nicht zu wissen, welches geholfen hat.

Bricht nginx nach einer Änderung ganz weg, spielen Sie die Kopie zurück und laden neu:

cp -a /root/backups/default.bak /etc/nginx/sites-available/default
nginx -t
systemctl reload nginx

Startet nginx nach einem restart nicht mehr, sagt systemctl status nginx selten genug. Aussagekräftiger:

journalctl -u nginx --since "10 min ago" --no-pager

Häufigster Grund für ein fehlgeschlagenes restart bei syntaktisch einwandfreier Konfiguration ist ein belegter Port 80 oder 443, meist ein Prozess aus dem vorigen Lauf. ss -ltnp | grep ':80' zeigt den Übeltäter.

Woran Sie erkennen, dass es wirklich behoben ist

Ein Befehl ohne Fehlermeldung beweist gar nichts. systemctl reload ist auch dann still, wenn sich fachlich nichts geändert hat, und nginx -t prüft nur Syntax. Belastbar sind diese vier Nachweise:

  1. Statuscode direkt am Server abfragen, damit weder Zwischenspeicher noch ein vorgelagerter Dienst das Ergebnis verfälscht:
    curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/
    Erwartet wird 200, nicht 502. Bei mehreren virtuellen Hosts den Namen mitgeben: curl -H "Host: example.com" ...
  2. Das Fehlerprotokoll bleibt still. Kürzen Sie es vor dem Test mit truncate -s 0 /var/log/nginx/error.log, lösen Sie mehrere Anfragen aus, sehen Sie erneut hinein. Eine leere Datei ist der eigentliche Beweis.
  3. FPM antwortet am Socket vorbei an nginx, per cgi-fcgi und als www-data. Damit ist Rechte- und Pfadfrage in einem Schritt erledigt.
  4. Ein Neustart ändert nichts. Der wichtigste und am häufigsten übersprungene Punkt. Viele Sofortmaßnahmen (von Hand gesetzte Rechte, manuell angelegte Verzeichnisse unter /run, ein gestarteter, aber nicht aktivierter Dienst) überstehen keinen Neustart. Prüfen Sie systemctl is-enabled php8.2-fpm nginx und starten Sie den Server einmal kontrolliert neu, solange Sie noch hinsehen, statt es dem nächsten Wartungsfenster zu überlassen.

Bei den KVM-Rootservern und Dedicated Servern von KernelHost erledigen Sie diesen Neustart samt Konsolenzugriff im Kundenbereich, auch wenn der Webdienst gerade nicht erreichbar ist. Die Server stehen im Rechenzentrum maincubes in Frankfurt am Main (TÜV TIER3+), angebunden an ein eigenes Netz mit DDoS-Schutz. Weiterführend: nginx 504 Gateway Time-out beheben und PHP-FPM pm.max_children richtig berechnen.

Kurzcheckliste für den Ernstfall

  1. tail -f /var/log/nginx/error.log, Anfrage auslösen, Fehlernummer notieren.
  2. Nummer 2 oder 111: läuft der Dienst, stimmt der Pfad. ss -lx | grep php gegen grep -Rn "fastcgi_pass" /etc/nginx/.
  3. Nummer 13: Rechte in der Pool-Datei, nicht per chmod.
  4. Nummer 104 oder 110: FPM-Protokoll und slowlog lesen, erst danach über Fristen reden.
  5. Meldung "too big header": Puffergrößen erhöhen.
  6. Nach dem Fix: Protokoll kürzen, erneut testen, Server einmal neu starten.

Häufige Fragen

Warum sehe ich 502 und nicht 504, obwohl die Seite einfach nur langsam ist?
Läuft die Frist von nginx ab (fastcgi_read_timeout, Standard 60 Sekunden), antwortet nginx mit 504 Gateway Time-out. Ein 502 entsteht bei langen Anfragen typischerweise dann, wenn PHP-FPM den Arbeitsprozess vorher hart beendet, meist durch request_terminate_timeout. nginx sieht dann nur noch eine abgebrochene Verbindung und protokolliert 'recv() failed (104: Connection reset by peer)'. Ordnen Sie die Fristen von innen nach außen aufsteigend, dann bekommen Sie lesbare PHP-Fehler statt 502.
Nach dem Upgrade auf Debian 13 sind alle PHP-Seiten 502. Was muss ich ändern?
Der Socket trägt die PHP-Version im Namen. Debian 13 bringt PHP 8.4, der Socket heißt /run/php/php8.4-fpm.sock, in der nginx-Konfiguration steht aber noch der Pfad aus Debian 12 mit 8.2. Passen Sie fastcgi_pass in allen aktiven vhost-Dateien an, prüfen Sie mit 'grep -Rn "fastcgi_pass" /etc/nginx/' und 'ls -l /run/php/', ob beide Seiten denselben Pfad zeigen, und laden Sie nginx danach neu. Bei Ubuntu 22.04 auf 24.04 ist es derselbe Effekt (8.1 auf 8.3).
Reicht 'nginx -t' als Nachweis, dass der Fehler behoben ist?
Nein. 'nginx -t' prüft ausschließlich die Syntax der Konfiguration. Ein Socket-Pfad, den es im System gar nicht gibt, ist syntaktisch völlig korrekt und liefert trotzdem bei jeder Anfrage einen 502. Belastbar ist erst ein Statuscode-Test am Server selbst, etwa 'curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/', zusammen mit einem Fehlerprotokoll, das dabei leer bleibt.
Wie finde ich im Fehlerprotokoll die Zeile, die zu meinem 502 gehört?
Halten Sie 'tail -f /var/log/nginx/error.log' in einem Terminal offen und lösen Sie die Anfrage in einem zweiten aus. Die dabei neu erscheinenden Zeilen sind die richtigen. Achten Sie darauf, dass viele vhosts ein eigenes error_log haben, prüfbar mit 'grep -Rn "error_log" /etc/nginx/nginx.conf /etc/nginx/sites-enabled/'. Das große -R ist dabei entscheidend, denn in sites-enabled liegen nur Symlinks, denen das kleine -r nicht folgt, und dann bleibt genau die vhost-eigene error_log-Zeile unsichtbar. Meldungen zu 'Permission denied' haben oft die Stufe [crit] statt [error], filtern Sie deshalb besser auf das Wort 'upstream'.
Der 502 tritt nur bei angemeldeten Nutzern auf, die Startseite lädt normal. Woran liegt das?
Das ist fast immer die Meldung 'upstream sent too big header while reading response header from upstream'. Angemeldete Sitzungen bringen größere Cookies und zusätzliche Kopfzeilen mit, die den Antwortpuffer von nginx sprengen. Erhöhen Sie fastcgi_buffer_size und fastcgi_buffers im Server- oder Location-Block, bei proxy_pass entsprechend proxy_buffer_size und proxy_buffers.
Ich habe die Rechte am Socket per chmod korrigiert, nach einem Neustart ist der Fehler zurück. Warum?
PHP-FPM legt die Socket-Datei bei jedem Start neu an und setzt dabei die Werte aus listen.owner, listen.group und listen.mode in der Pool-Datei. Ein chmod von Hand hält deshalb nur bis zum nächsten Start des Dienstes. Tragen Sie die Rechte in /etc/php/<version>/fpm/pool.d/www.conf ein und laden Sie FPM neu.

nginx PHP-FPM 502 Bad Gateway Debian Ubuntu Fehlerbehebung Webserver Linux-Administration