Een 504 Gateway Timeout-fout betekent dat een server die als gateway of proxy werkt, wachtte op een antwoord van de server erachter en het daarna opgaf. Het verzoek kwam aan bij je CDN, load balancer of webserver, werd doorgegeven aan de applicatie, en de applicatie reageerde niet voordat de tijdslimiet verstreken was.
De server achter de proxy draait vaak gewoon nog. Hij is alleen te traag, of iets waarop hij wacht is dat. Daarom is een 504 anders dan de meeste storingen: dingen herstarten lost het zelden voor lange tijd op. Deze gids laat zien hoe je vindt welke timeout afging, wat een verzoek meestal traag maakt en hoe je de oorzaak oplost in plaats van het symptoom.
Wat een 504 je vertelt
Een verzoek aan een moderne website gaat door meerdere lagen, en elke laag heeft een eigen limiet voor hoe lang hij op de volgende wacht:
Een CDN zoals Cloudflare wacht een vaste tijd op je origin.
Een load balancer heeft per target een idle- of response-timeout.
nginx wacht op de upstream volgens proxy_read_timeout of fastcgi_read_timeout, standaard 60 seconden.
De applicatie heeft eigen limieten, zoals max_execution_time in PHP of een worker-timeout in Gunicorn.
De 504 komt van de eerste laag waarvan de limiet verloopt. De buren betekenen iets anders: een 502 Bad Gateway betekent dat de upstream iets ongeldigs of helemaal niets terugstuurde, en een 503 Service Unavailable betekent dat de dienst het verzoek weigerde omdat hij overbelast is of in onderhoud.
Vind de timeout die afging
Meet hoe lang het verzoek duurt. Een 504 die altijd na hetzelfde aantal seconden komt, wijst naar één specifieke limiet:
curl -s -o /dev/null -w “status %{http_code} after %{time_total}s\n” https://www.example.com/reports
status 504 after 60.04s
Bekijk daarna de response-headers en de foutpagina om te zien welke laag antwoordde, net als bij elke 5xx-fout. Een kale nginx-pagina met server: nginx betekent dat je eigen webserver een timeout kreeg. Een pagina in de huisstijl van het CDN die je host noemt, betekent dat het CDN een timeout kreeg terwijl het op je origin wachtte.
nginx logt de timeout met het adres waarop hij wachtte:
upstream timed out (110: Connection timed out) while reading response header from upstream,
upstream: “fastcgi://unix:/run/php/php8.3-fpm.sock”, request: “GET /reports HTTP/2.0”
Nu weet je welke pagina traag is en welk deel van de stack haar liet wachten. De volgende stap is uitzoeken waarom.
Veelvoorkomende oorzaken en hoe je ze oplost
Trage databasequery’s
De meest voorkomende reden. Een query die bij duizend rijen 50 milliseconden duurde, duurt bij een miljoen rijen 40 seconden, omdat hij de hele tabel doorzoekt. Zet de slow query log aan en zoek naar de query’s van die pagina:
# MySQL / MariaDB
SET GLOBAL slow_query_log = ‘ON’;
SET GLOBAL long_query_time = 1;
# PostgreSQL, in postgresql.conf
log_min_duration_statement = 1000
Voer de traagste query uit met EXPLAIN en kijk of er volledige tabelscans zijn. Een ontbrekende index is meestal de oplossing. Locks zijn de andere gebruikelijke verdachte: een lange transactie of een migratie kan een tabel vasthouden terwijl elk verzoek dat die tabel nodig heeft, wacht.
Trage externe API’s
Pagina’s roepen tijdens het opbouwen vaak andere diensten aan: een betaalprovider, een verzendkostencalculator, een zoekmachine, een CRM. Is die dienst traag, dan is je pagina traag en krijgt je proxy een timeout. Stel op elke uitgaande aanroep een korte timeout in, een paar seconden in plaats van de standaard van de library, en bepaal wat de pagina toont als de aanroep mislukt. Een verzendschatting met “wordt berekend bij het afrekenen” is beter dan een 504.
Houd de diensten waarvan je afhankelijk bent in de gaten. De monitoring van externe diensten van Uptimecheck volgt de statuspagina’s van 31 diensten zoals Klarna, Shopify en Cloudflare, zodat een trage provider naast je eigen checks verschijnt.
Te weinig workers voor het verkeer
Als elke worker bezig is, wachten nieuwe verzoeken in een wachtrij. Ze zijn zelf niet traag, ze wachten op hun beurt, en de klok van de proxy loopt al die tijd door. PHP-FPM meldt dat in zijn log met server reached pm.max_children. Meer workers helpen alleen als de server er geheugen en CPU voor heeft. Vaak is het beter om elk verzoek korter te maken, zodat dezelfde workers er meer afhandelen, en pagina’s te cachen die niet per bezoeker verschillen.
Lange taken binnen een webverzoek
Exports, imports, rapporten genereren, afbeeldingen verwerken en honderden e-mails versturen horen niet in een webverzoek. Ze duren zo lang als ze duren, en vroeg of laat overschrijdt er een een timeout. Verplaats ze naar een achtergrondwachtrij: het verzoek start de taak en antwoordt meteen, en de pagina vraagt het resultaat periodiek op of de gebruiker krijgt een e-mail als het klaar is.
De server zelf is overbelast
Een hoge CPU-belasting, geheugendruk die de server laat swappen of een schijf die het niet bijhoudt, maken alles tegelijk traag. Een 504 op elke pagina, niet op één, wijst hierop. Bekijk CPU, geheugen, swap en disk-wachttijd voor dezelfde periode:
uptime
free -m
iostat -x 5 3
Servermonitoring bewaart die geschiedenis, zodat je ziet wat de server deed op de minuut dat de 504’s begonnen, in plaats van achteraf te gissen.
Netwerkproblemen tussen de lagen
Als de proxy de upstream helemaal niet bereikt, bijvoorbeeld omdat een firewall pakketten laat vallen in plaats van ze te weigeren, blijft de verbinding hangen tot de timeout. Dat eindigt in een 504 in plaats van een 502. Controleer vanaf dezelfde machine of de proxy een verbinding kan openen met het adres en de poort van de upstream.
Wanneer een hogere timeout terecht is
Soms duurt een verzoek terecht lang: een grote upload, een rapport dat een beheerder één keer per maand opvraagt. Verhoog de limiet dan alleen voor dat pad, en houd de lagen op volgorde, zodat de buitenste langer wachten dan de binnenste:
location /admin/exports/ {
proxy_read_timeout 300s;
proxy_pass http://app;
}
De limiet voor de hele site verhogen lost trage pagina’s niet op. Bezoekers wachten dan langer voordat ze een fout zien, en trage verzoeken houden workers langer bezet, waardoor de wachtrij voor iedereen erger wordt.
Hoe monitoring 504’s opvangt
Een 504 komt zelden uit het niets. De pagina werd elke week een beetje trager naarmate de data groeide, tot ze op een dag de limiet overschreed. Dat is goed nieuws, want het betekent dat je het kunt zien aankomen.
Let op de responstijd, niet alleen op de status. Uptimecheck registreert de responstijd van elke check, opgesplitst in DNS, connect, TLS, server en download, zodat je ziet of de server trager werd of het netwerk. Een melding bij trage responses laat je weten wanneer een pagina de limiet overschrijdt die jij instelt, lang voor de timeout van de proxy. Onze gids over wat een goede responstijd is helpt je die limiet te kiezen.
Bevestig fouten voordat je alarm slaat. Checks draaien zo vaak als elke minuut vanuit Stockholm, Londen en New York, en elke fout wordt vanaf een tweede locatie bevestigd, zodat één traag verzoek niemand wakker maakt.
Monitor de trage pagina’s direct. Zoeken, afrekenen, accountpagina’s en rapporten zijn waar 504’s ontstaan, en dat is zelden de homepage. Voeg er uptime monitors voor toe, met een timeout die past bij wat een bezoeker accepteert.
504-checklist
Meet hoe lang het verzoek duurt: een rond aantal seconden vertelt je welke limiet afging.
Lees de headers en de foutpagina om te zien welke laag een timeout kreeg.
Zoek de trage pagina op in de error log van de proxy.
Zoek naar trage query’s, locks en trage externe aanroepen voor die pagina.
Controleer workers, CPU, geheugen, swap en schijf voor dezelfde minuten.
Maak het trage deel sneller, cache het of verplaats het naar een achtergrondtaak.
Verhoog timeouts alleen voor paden die terecht lang duren, buitenste lagen langer dan binnenste.
Stel meldingen in voor trage responses, zodat je de volgende 504 ziet terwijl het nog een vertraging is.