502 Bad Gateway: what it means and how to fix it (nginx, Cloudflare, load balancers)

The page you see came from the middleman, not the website itself. Something in front of the app (nginx, a CDN, a load balancer) asked the app for the page and got nothing usable back.

Who is saying what

Most sites have a chain: browser, then a CDN or load balancer, then a web server such as nginx, then the app (Node, Python, PHP-FPM). A 502 is sent by one of the middle links when the link behind it failed to give a proper HTTP response. So the cause is almost always the app or the connection to it, not the proxy that shows the error.

502 vs 503 vs 504

CodeMeaningTypical cause
502 Bad GatewayThe backend gave no valid responseApp not running, wrong port, app crashed mid-request
503 Service UnavailableThe server is up but refusing work for nowMaintenance, overload, no healthy backends
504 Gateway TimeoutThe backend took too longSlow query or slow upstream API, timeout too short

All three can be retried, ideally with a growing delay. Anvil’s free HTTP status lookup lists retry advice for every status code.

Fixing it behind nginx

Start with the error log, usually /var/log/nginx/error.log. The message tells you which case you have:

Log saysMeaning and fix
connect() failed (111: Connection refused) while connecting to upstreamNothing listens where proxy_pass points. Start the app, or fix the port. Same checks as localhost refused to connect.
connect() to unix:/run/php/php8.3-fpm.sock failed (2: No such file or directory)The PHP-FPM socket path in nginx doesn’t match the running PHP version, or PHP-FPM is stopped.
(13: Permission denied) while connecting to upstreamnginx may not open the socket, or on SELinux systems it may not make network connections: setsebool -P httpd_can_network_connect 1.
upstream prematurely closed connectionThe app crashed or was killed during the request. Check the app’s own logs and memory (the kernel’s out-of-memory killer shows in dmesg).
upstream sent too big headerLarge cookies or headers: raise proxy_buffer_size (or fastcgi_buffer_size).
no live upstreamsEvery backend in the upstream block failed its checks recently.

Two classic mix-ups: proxy_pass http://localhost:3000 where localhost resolves to IPv6 ::1 but the app listens only on 127.0.0.1 (write 127.0.0.1 explicitly), and nginx in Docker pointing at localhost, which is the nginx container itself rather than the app container (use the service name).

Cloudflare and other CDNs

If you are just visiting

There’s nothing wrong with your device. Reload after a minute, and if it persists, the site is down for everyone. Clearing cookies helps only in the rare “too big header” case.

App keeps restarting with exit code 137 or Killed in its logs? It is running out of memory: see exit code 137 and the OOM killer.

Related

Cloudflare Error 523 · Cloudflare Error 520 · Cloudflare Error 525 · Cloudflare Error 526 · Cloudflare Error 521 · Cloudflare Error 522 · Cloudflare Error 524 · HTTP 504 Gateway Timeout · HTTP 503 Service Unavailable · HTTP 429 Too Many Requests · ECONNRESET / read ECONNRESET · WebSocket connection failed · download won't resume

Questions

Is a 502 Bad Gateway my fault?

Almost never, if you are a visitor. It means a server in front of the website couldn't get a proper answer from the site's own app. Wait and reload.

What is the difference between 502 and 504?

502 means the backend answered badly or refused the connection. 504 means it didn't answer in time. 502 points to an app that is down or crashing, 504 to one that is slow.

How do I fix 502 Bad Gateway in nginx?

Read /var/log/nginx/error.log. “Connection refused” means the app isn't running on the proxy_pass address, a missing socket means PHP-FPM is stopped or misnamed, and “prematurely closed” means the app crashed during the request.

Should a client retry after a 502?

Yes, a 502 is usually temporary. Retry a few times with a growing delay, and only automatically for requests that are safe to repeat.

Published .

Try it

Related guides

Newest guides