nginx 502 Bad Gateway oplossen: oorzaken en oplossingen

Gepubliceerd op 16 min leestijd

502 Bad Gateway betekent: nginx heeft van de backend geen geldig antwoord gekregen. De vijf meest voorkomende oorzaken, de juiste regel in het foutlog en hoe u aantoont dat de fix werkelijk werkt.

Wat "502 Bad Gateway" werkelijk betekent

Een 502 komt niet van uw applicatie, hij komt van nginx. nginx heeft de aanvraag aangenomen, doorgegeven aan een backend (PHP-FPM, Node, Python, een andere webserver) en daarvandaan geen bruikbaar antwoord gekregen. Daarom staat er op de foutpagina niets nuttigs.

Het onderscheid met de aangrenzende statuscodes bespaart in een noodgeval veel tijd:

  • 500 Internal Server Error: de backend heeft geantwoord, maar het antwoord was een fout. De oorzaak ligt in de applicatiecode. Lees het log van de applicatie, niet dat van nginx.
  • 502 Bad Gateway: de verbinding met de backend kwam niet tot stand of brak af voordat er een volledig antwoord was.
  • 504 Gateway Time-out: de verbinding stond, maar de backend zweeg te lang en nginx verloor zijn geduld.

Dit onderscheid is de belangrijkste hefboom bij time-outs, want dezelfde trage pagina verschijnt de ene keer als 502 en de andere keer als 504, afhankelijk van wie het eerst afbreekt. Verderop meer daarover.

De pakketsituatie op Debian 13, Debian 12, Ubuntu 24.04 en Ubuntu 22.04

nginx gedraagt zich bij 502-fouten op alle vier de systemen hetzelfde, de directives heten identiek. De verschillen zitten bijna volledig aan de PHP-kant, en precies daaruit ontstaan de meeste 502's na een distributiewissel.

SysteemnginxPHPServicenaamSocket
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

Vervang in alle volgende commando's het versienummer door dat van uw eigen systeem. Alle voorbeelden gaan uit van een root-shell, zet er anders sudo voor. Welke versie geïnstalleerd is, verraadt een blik op de FPM-binaries, ook als de service helemaal niet start:

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

Eerst het foutlog: de juiste regel vinden

De meest gemaakte fout bij de diagnose is zoeken in het verkeerde log. nginx heeft een globaal foutlog en per virtuele host vaak nog een eigen log. Welk bestand geldt, staat in de configuratie:

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

Let op de hoofdletter -R. In /etc/nginx/sites-enabled/ staan op Debian en Ubuntu uitsluitend symlinks naar sites-available, en GNU grep volgt met de kleine -r bij het recursief aflopen geen enkele symlink. Met -rn krijgt u daarom alleen de treffers uit nginx.conf, terwijl de vhost-eigen error_log-regel onzichtbaar blijft: precies die regel waar u bij een 502 naar zoekt, want het globale log bevat de FastCGI-fout niet zodra de vhost omleidt. Wie liever bij -r blijft, greppt de bronmappen rechtstreeks:

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

Zonder eigen opgave in het serverblok komt alles in /var/log/nginx/error.log terecht. De betrouwbaarste weg naar de juiste regel loopt via een live-opname: houd het log in één terminal open, activeer de aanvraag in een tweede en bekijk de regels die er daarbij nieuw bij komen.

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

Als alternatief filtert u op het tijdstempel. nginx schrijft lokale tijd in het formaat 2026/07/26 09:14:22, niet in UTC. Een vergelijking met een klok in een andere tijdzone gaat geregeld mis.

Een 502-regel is altijd volgens hetzelfde patroon opgebouwd. Voorbeeld:

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 onderdelen dragen alle informatie:

  1. De systeemaanroep: connect(), recv(), send(). connect() betekent dat er nooit een verbinding tot stand kwam. recv() betekent dat de verbinding stond en daarna afbrak.
  2. Het foutnummer tussen haakjes, zie de tabel hieronder. Dat is de eigenlijke diagnose.
  3. De fase: while connecting to upstream tegenover while reading response header from upstream. Het eerste is een bereikbaarheidsprobleem, het tweede een runtime- of crashprobleem.
  4. Het veld upstream:. Daar staat het pad of het adres dat nginx werkelijk heeft gebruikt. Niet wat u in de configuratie vermoedt, maar wat er actief geladen is.
MeldingBetekenisSectie
2: No such file or directorySocketbestand bestaat nietService dood of pad verkeerd
13: Permission deniedSocket bestaat, nginx mag er niet bijRechten
111: Connection refusedNiets luistert op adres en poortBackend niet bereikbaar
110: Connection timed outGeen antwoord binnen de termijnTime-out
104: Connection reset by peerBackendproces is midden in de aanvraag gestorvenCrashes en limieten
11: Resource temporarily unavailableWachtrij van de socket volCrashes en limieten

De regel bij 13: Permission denied krijgt bij nginx vaak het niveau [crit] in plaats van [error]. Wie alleen op [error] filtert, ziet hem over het hoofd. Filter daarom liever op de tekst:

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

De tweede helft van de waarheid staat in het log van PHP-FPM, standaard onder /var/log/php8.2-fpm.log. Bij crashes en limieten staat daar de reden, terwijl nginx alleen het symptoom ziet.

Oorzaak 1: PHP-FPM draait niet

Klassiek foutnummer 2. Controleer eerst de toestand van de service:

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

is-active antwoordt met één woord, dat volstaat voor een script. Komt er inactive of failed uit, haal de reden dan uit de journal, en wel met een tijdvenster in plaats van de laatste tien regels:

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

Heel vaak is de oorzaak een kapotte poolconfiguratie die na een reload is blijven liggen. FPM heeft een eigen syntaxtest die zonder herstart draait:

php-fpm8.2 -t

Typische startfouten, letterlijk, en wat ze betekenen:

  • ERROR: [pool www] cannot get uid for user 'webuser': de systeemgebruiker die bij user = is ingevuld, bestaat niet meer, bijvoorbeeld na een migratie.
  • ERROR: unable to bind listening socket for address '/run/php/php8.2-fpm.sock': No such file or directory (2): de map /run/php ontbreekt. Die staat op een tmpfs en wordt bij het starten van de service aangemaakt. Wie listen naar een pad daarbuiten laat wijzen, moet de map zelf laten aanmaken.
  • ERROR: An another FPM instance seems to already listen on ...: een proces uit een mislukte herstart hangt nog aan de socket.

Waaraan u merkt dat het werkelijk opgelost is: niet aan het feit dat systemctl restart zonder uitvoer doorliep. Een FPM-master start ook als er geen enkel werkproces aanvragen kan aannemen. Veelzeggend is dat de socket zichtbaar is in het systeem en dat FPM erop antwoordt.

ss -lx | grep php

Voor de echte antwoordtest activeert u in /etc/php/8.2/fpm/pool.d/www.conf de regel ping.path = /ping, laadt u FPM opnieuw en bevraagt u de socket rechtstreeks, volledig langs nginx heen:

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

Komt er pong terug, dan is de PHP-kant in orde en zit de fout tussen nginx en de socket. Komt er niets terug, dan hoeft u bij nginx helemaal niet verder te zoeken.

Oorzaak 2: verkeerd socketpad

Dit is op Debian en Ubuntu veruit de meest voorkomende oorzaak, omdat de socket de naam van de PHP-versie draagt, de nginx-configuratie die naam hard vastlegt, en een distributie-upgrade beide uit elkaar trekt.

Concreet: een upgrade van Debian 12 naar Debian 13 tilt PHP van 8.2 naar 8.4. De oude socket /run/php/php8.2-fpm.sock verdwijnt, in het vhost-bestand staat hij nog steeds. Het resultaat is een 502 op elke afzonderlijke PHP-pagina, meteen na de herstart. Hetzelfde gebeurt bij Ubuntu 22.04 naar 24.04 (8.1 naar 8.3).

Een tweede valkuil zit in de meegeleverde voorbeeldconfiguratie. In /etc/nginx/sites-available/default staat een uitgecommentarieerd blok waarvan de fastcgi_pass naar een PHP-versie wijst die al jaren niet meer actueel is. Wie die regels alleen maar uit commentaar haalt, heeft de 502 daarmee juist zelf veroorzaakt.

Vergelijk beide kanten. Wat nginx wil gebruiken:

grep -Rn "fastcgi_pass" /etc/nginx/

Wat FPM werkelijk aanbiedt:

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

De toevoeging *= in het zoekpatroon is opzet, die eist achter listen een willekeurig aantal spaties en dan een isgelijkteken. Een kaal ^listen raakt namelijk ook listen.owner, listen.group en listen.mode, en dan gaat de gezochte regel tussen de treffers verloren. De wildcard /etc/php/*/ is daarentegen juist zo bedoeld, die dekt elke geïnstalleerde PHP-versie af. En wat er op het draaiende systeem bestaat:

ls -l /run/php/

De drie uitvoeren moeten hetzelfde pad tonen. Belangrijk: grep -R over /etc/nginx/ in plaats van alleen over dat ene bestand dat u verdenkt. Via include ingevoegde fragmenten zijn een geliefde schuilplaats, net als oude bestanden in sites-available die via een vergeten symlink in sites-enabled nog actief zijn. Ook hier geldt: alleen de hoofdletter -R volgt die symlinks en laat u daarmee zien welk bestand werkelijk actief is.

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

Voordat u iets wijzigt, maakt u een kopie. Dat kost twee seconden en bespaart u in het ergste geval een herstel uit de back-up:

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

Wie meerdere keren ingrijpt, hangt er beter een tijdstempel aan (default.bak.$(date +%F-%H%M)), want cp -a overschrijft een bestaande .bak zonder enige waarschuwing.

Na de correctie altijd eerst testen, dan laden. reload in plaats van restart, zodat bestaande verbindingen niet wegvallen:

nginx -t
systemctl reload nginx

Let op: nginx -t controleert uitsluitend de syntaxis. Een socketpad dat niet bestaat, geldt als volkomen geldige configuratie. Een groen syntax is ok is daarom geen bewijs dat de 502 weg is.

Oorzaak 3: rechten op de socket

Foutnummer 13. De socket is er, nginx mag hem alleen niet openen. nginx draait op Debian en Ubuntu als gebruiker www-data, en de standaardpool van FPM maakt de socket daar passend bij aan. Dat is zichtbaar in het poolbestand:

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

Met listen.owner = www-data, listen.group = www-data en modus 0660 werkt het samenspel vanzelf. Het kan in drie situaties misgaan:

  • Een eigen pool per project. Worden user en group op een projectgebruiker gezet, dan moet listen.group toch een groep zijn waar nginx lid van is. Gebruikelijk is listen.owner = projectgebruiker samen met listen.group = www-data.
  • Socket buiten /run. Niet alleen het socketbestand moet toegankelijk zijn, ook elke map onderweg ernaartoe heeft het uitvoerrecht voor nginx nodig. Een socket in een homedirectory met modus 0700 is voor niemand bereikbaar behalve voor de eigenaar.
  • nginx met een gewijzigde user in /etc/nginx/nginx.conf.

U bevestigt de verdenking zonder te gokken door de toegang precies te proberen als de gebruiker die hem in bedrijf nodig heeft:

id www-data
sudo -u www-data test -w /run/php/php8.2-fpm.sock && echo "Toegang aanwezig" || echo "geen toegang"

Nog veelzeggender is de cgi-fcgi-aanroep uit de vorige paragraaf, eveneens met sudo -u www-data ervoor. Antwoordt FPM als root, maar niet als www-data, dan is de diagnose eenduidig.

Zet de waarden in het poolbestand, niet met chmod op het socketbestand. Een chmod 666 houdt precies stand tot de volgende herstart van FPM, dan maakt FPM de socket opnieuw aan met de geconfigureerde rechten, en is de fout terug, meestal op het ongelegenste moment.

Op Debian en Ubuntu is AppArmor actief. Een meegeleverd profiel voor nginx wordt in de standaardtoestand niet afgedwongen, maar kan door hardeningsjablonen scherp gezet zijn. Blijft een melding met nummer 13 bestaan ondanks correcte rechten, dan loont een blik in aa-status en in journalctl -k | grep DENIED.

Oorzaak 4: time-out bij lange aanvragen

Hier scheidt een nette werkwijze zich van giswerk, want het puur verstrijken van de nginx-termijn levert een 504 op, geen 502. Eindigt een lange aanvraag als 502, dan heeft bijna altijd PHP-FPM het werkproces daarvoor al opgeruimd, en zag nginx alleen nog een afgebroken verbinding. In het log staat dan typisch:

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

Drie termijnen werken tegelijk, en hun volgorde bepaalt de statuscode:

  1. max_execution_time in php.ini, standaard 30 seconden in FPM-bedrijf. Telt alleen de looptijd van het script. Wachttijd in systeemaanroepen, bijvoorbeeld op een hangende databasequery, telt onder Linux niet mee. Daarom redt deze waarde u juist niet bij het probleem waarbij u dat verwacht.
  2. request_terminate_timeout in het poolbestand, in de standaardtoestand uit. Beëindigt het werkproces hard, ongeacht waar het op hangt. Dit is de waarde die 502's produceert.
  3. fastcgi_read_timeout in nginx, standaard 60 seconden. Verstrijkt die, dan volgt een 504.

De bruikbare volgorde loopt oplopend van binnen naar buiten, zodat altijd eerst de laag ingrijpt die nog een begrijpelijke foutmelding kan produceren. Bijvoorbeeld 60, dan 75, dan 90 seconden. Andersom gesorteerd krijgt u 502's in plaats van leesbare PHP-fouten.

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

Wat FPM heeft opgeruimd, staat in het log daarvan in gewone taal:

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

Voordat u termijnen verhoogt, laat u zich eerst tonen waar de tijd blijft. FPM heeft daarvoor een eigen log dat bij overschrijding een volledige PHP-aanroepstack wegschrijft. In het poolbestand activeren:

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

Na een systemctl reload php8.2-fpm staat daar bij de volgende trage aanvraag de functie inclusief regelnummer die blijft hangen. In de praktijk is dat in vier van de vijf gevallen een databasequery zonder index of een aanroep naar een externe programmeerinterface zonder eigen termijn. Termijnen omhoog draaien verlengt dan alleen de tijd tot de fout en blokkeert bovendien werkprocessen.

Oorzaak 5: backend niet bereikbaar

Betreft elke backend die via TCP wordt aangesproken: FPM op poort 9000, een Node-applicatie, een Java-service, een container. De leidende melding is foutnummer 111.

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

Controleer eerst of er überhaupt iets luistert, en vooral waarop:

ss -ltnp

Dit commando toont uitsluitend TCP-sockets, en daaruit ontstaat een wijdverbreide denkfout: een PHP-FPM-pool in de standaardtoestand luistert op een Unix-socket onder /run/php/ en verschijnt in deze lijst helemaal niet, hoewel hij prima draait. Zichtbaar wordt hij pas zo:

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

Voor FPM is ss -ltnp dus alleen veelzeggend als de pool via listen = 127.0.0.1:9000 bewust op TCP is omgezet. Bij Node-, Java- of containerbackends is het daarentegen precies het juiste commando.

Drie struikelblokken die zelden in handleidingen staan:

  • localhost lost eerst op naar ::1. Staat er in nginx proxy_pass http://localhost:3000; terwijl de applicatie alleen op 127.0.0.1 luistert, dan probeert nginx het IPv6-adres en krijgt het "Connection refused". De service draait, de poort staat open, en toch een 502. Oplossing: schrijf in nginx 127.0.0.1 voluit, of laat de applicatie aan beide adresfamilies binden.
  • nginx lost namen eenmalig bij het laden op. Staat er in de proxy_pass een hostnaam, dan onthoudt nginx het adres. Wisselt de backend van IP-adres, bijvoorbeeld bij een opnieuw gestarte container, dan lopen de aanvragen tot de volgende reload in het niets.
  • Firewall op de terugweg. Bij een backend op een andere server verschijnt 113: No route to host of een time-out in plaats van "Connection refused". Controleer met ufw status en met een directe verbindingstest vanaf de nginx-server.

Wordt er een upstream-blok met meerdere doelen gebruikt, dan komt daar een eigen melding bij:

no live upstreams while connecting to upstream

Dat betekent dat nginx alle doelen na herhaalde mislukte pogingen voor de duur van fail_timeout uit het verkeer heeft genomen. Ook na reparatie van de backend duurt het dan nog tot die termijn verstreken is voordat er weer aanvragen doorkomen. Een systemctl reload nginx zet die toestand meteen terug.

De 502 die bij geen van de vijf oorzaken past

Twee gevallen zien eruit als een storing, maar zijn het niet, en kosten daarom bovengemiddeld veel tijd.

Antwoordheader te groot. De applicatie draait foutloos, alleen leveren losse aanvragen een 502 op:

upstream sent too big header while reading response header from upstream

Aanleiding zijn grote cookies of sessiekenmerken in headerregels, de buffer van nginx is te klein. In het server- of locationblok:

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

Bij proxy_pass heten de directives proxy_buffer_size en proxy_buffers. Typisch is dat alleen ingelogde gebruikers er last van hebben, terwijl de startpagina foutloos laadt.

Werkprocessen op. Onder belasting verschijnt er in het FPM-log:

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

Nieuwe aanvragen wachten dan in de wachtrij van de socket. Is ook die vol, dan meldt nginx 11: Resource temporarily unavailable. Voordat u pm.max_children verhoogt, rekent u het even na: beschikbaar werkgeheugen gedeeld door het werkelijke verbruik van één werkproces. Een te hoge waarde ruilt 502's in voor een systeemtoestand waarin het geheugen opraakt, en dat treft dan ook de database.

Crashes. Regels met exited on signal 11 (SIGSEGV) wijzen op een defecte PHP-extensie, vaak na een wissel van PHP-versie met achtergebleven modules uit de vorige versie.

Als de ingreep niets oplevert: de weg terug

Twee regels houden de schade klein. Ten eerste: één wijziging tegelijk, met een kopie van het originele bestand onder /root/backups, nooit in de webmap. Ten tweede: na elke stap tegencontroleren, in plaats van drie dingen tegelijk te wijzigen en achteraf niet te weten wat er geholpen heeft.

Valt nginx na een wijziging helemaal weg, speel dan de kopie terug en laad opnieuw:

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

Start nginx na een restart niet meer, dan zegt systemctl status nginx zelden genoeg. Veelzeggender:

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

De meest voorkomende reden voor een mislukte restart bij een syntactisch foutloze configuratie is een bezette poort 80 of 443, meestal een proces uit de vorige run. ss -ltnp | grep ':80' toont de boosdoener.

Waaraan u merkt dat het werkelijk verholpen is

Een commando zonder foutmelding bewijst helemaal niets. systemctl reload blijft ook stil als er inhoudelijk niets veranderd is, en nginx -t controleert alleen de syntaxis. Deze vier bewijzen zijn wel betrouwbaar:

  1. Vraag de statuscode rechtstreeks op de server op, zodat noch een cache noch een voorgeschakelde dienst het resultaat vervalst:
    curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/
    Verwacht wordt 200, niet 502. Geef bij meerdere virtuele hosts de naam mee: curl -H "Host: example.com" ...
  2. Het foutlog blijft stil. Kort het vóór de test in met truncate -s 0 /var/log/nginx/error.log, activeer meerdere aanvragen en kijk er opnieuw in. Een leeg bestand is het eigenlijke bewijs.
  3. FPM antwoordt op de socket langs nginx heen, via cgi-fcgi en als www-data. Daarmee zijn de rechtenvraag en de padvraag in één stap afgehandeld.
  4. Een herstart verandert niets. Het belangrijkste en meest overgeslagen punt. Veel noodmaatregelen (met de hand gezette rechten, handmatig aangemaakte mappen onder /run, een gestarte maar niet ingeschakelde service) overleven geen herstart. Controleer systemctl is-enabled php8.2-fpm nginx en herstart de server één keer gecontroleerd, zolang u er nog naar kijkt, in plaats van het aan het volgende onderhoudsvenster over te laten.

Bij de KVM-rootservers en dedicated servers van KernelHost voert u deze herstart inclusief consoletoegang uit in het klantenpaneel, ook als de webdienst op dat moment niet bereikbaar is. De servers staan in het datacenter maincubes in Frankfurt am Main (TÜV TIER3+), aangesloten op een eigen netwerk met DDoS-bescherming. Verder lezen: nginx 504 Gateway Time-out oplossen en PHP-FPM pm.max_children correct berekenen.

Korte checklist voor een noodgeval

  1. tail -f /var/log/nginx/error.log, aanvraag activeren, foutnummer noteren.
  2. Nummer 2 of 111: draait de service, klopt het pad. ss -lx | grep php tegenover grep -Rn "fastcgi_pass" /etc/nginx/.
  3. Nummer 13: rechten in het poolbestand, niet via chmod.
  4. Nummer 104 of 110: FPM-log en slowlog lezen, pas daarna over termijnen praten.
  5. Melding "too big header": buffergroottes verhogen.
  6. Na de fix: log inkorten, opnieuw testen, server één keer herstarten.

Veelgestelde vragen

Waarom zie ik een 502 en geen 504, terwijl de pagina alleen maar traag is?
Verstrijkt de termijn van nginx (fastcgi_read_timeout, standaard 60 seconden), dan antwoordt nginx met 504 Gateway Time-out. Een 502 ontstaat bij lange aanvragen meestal doordat PHP-FPM het werkproces daarvoor al hard beëindigt, vaak via request_terminate_timeout. nginx ziet dan alleen nog een afgebroken verbinding en logt 'recv() failed (104: Connection reset by peer)'. Zet de termijnen oplopend van binnen naar buiten, dan krijgt u leesbare PHP-fouten in plaats van 502's.
Na de upgrade naar Debian 13 geven alle PHP-pagina's een 502. Wat moet ik aanpassen?
De socket draagt de PHP-versie in zijn naam. Debian 13 brengt PHP 8.4 mee, de socket heet /run/php/php8.4-fpm.sock, maar in de nginx-configuratie staat nog het pad uit Debian 12 met 8.2. Pas fastcgi_pass in alle actieve vhost-bestanden aan, controleer met 'grep -Rn "fastcgi_pass" /etc/nginx/' en 'ls -l /run/php/' of beide kanten hetzelfde pad tonen, en laad nginx daarna opnieuw. Bij Ubuntu 22.04 naar 24.04 is het hetzelfde effect (8.1 naar 8.3).
Is 'nginx -t' voldoende bewijs dat de fout verholpen is?
Nee. 'nginx -t' controleert uitsluitend de syntaxis van de configuratie. Een socketpad dat op het systeem helemaal niet bestaat, is syntactisch volkomen correct en levert toch bij elke aanvraag een 502 op. Betrouwbaar is pas een statuscodetest op de server zelf, bijvoorbeeld 'curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1/', samen met een foutlog dat daarbij leeg blijft.
Hoe vind ik in het foutlog de regel die bij mijn 502 hoort?
Houd 'tail -f /var/log/nginx/error.log' in één terminal open en activeer de aanvraag in een tweede. De regels die daarbij nieuw verschijnen, zijn de juiste. Let erop dat veel vhosts een eigen error_log hebben, te controleren met 'grep -Rn "error_log" /etc/nginx/nginx.conf /etc/nginx/sites-enabled/'. De hoofdletter -R is daarbij doorslaggevend, want in sites-enabled staan alleen symlinks die de kleine -r niet volgt, en dan blijft juist de vhost-eigen error_log-regel onzichtbaar. Meldingen over 'Permission denied' hebben vaak het niveau [crit] in plaats van [error], filter daarom liever op het woord 'upstream'.
De 502 treedt alleen op bij ingelogde gebruikers, de startpagina laadt normaal. Waar ligt dat aan?
Dat is bijna altijd de melding 'upstream sent too big header while reading response header from upstream'. Ingelogde sessies brengen grotere cookies en extra headerregels mee, die de antwoordbuffer van nginx laten overlopen. Verhoog fastcgi_buffer_size en fastcgi_buffers in het server- of locationblok, bij proxy_pass navenant proxy_buffer_size en proxy_buffers.
Ik heb de rechten op de socket met chmod gecorrigeerd, na een herstart is de fout terug. Waarom?
PHP-FPM maakt het socketbestand bij elke start opnieuw aan en zet daarbij de waarden uit listen.owner, listen.group en listen.mode in het poolbestand. Een chmod met de hand houdt daarom alleen stand tot de volgende start van de service. Zet de rechten in /etc/php/<versie>/fpm/pool.d/www.conf en laad FPM opnieuw.

nginx PHP-FPM 502 Bad Gateway Debian Ubuntu Probleemoplossing Webserver Linux-beheer