502 Bad Gateway
502 Bad Gateway comes from a proxy or load balancer: it is up, but the server behind it (the upstream) refused the connection, closed it, or sent back something that was not valid HTTP. Look at the upstream, not the proxy.
A proxy or gateway got an invalid response, or no response, from the server behind it.
The proxy (nginx, a load balancer, a CDN) is working; the upstream application is not answering properly. Usual causes: the app process is down or restarting, it listens on a different port or socket than the proxy expects, or it crashed mid-request. Check the proxy's error log for the reason, then the upstream's logs.
Explained
There are two hops: client to proxy, and proxy to upstream. A 502 means the second hop failed fast. Compare 504, where the upstream was reachable but too slow, and 503, where the proxy knows there is no usable upstream.
nginx writes the exact reason to its error log. connect() failed (111: Connection refused) while connecting to upstream means nothing is listening at the address in proxy_pass or fastcgi_pass. upstream prematurely closed connection while reading response header means the app accepted the request and then died or closed the socket. no live upstreams means every server in the upstream block is marked as failed.
A common pattern with Gunicorn or similar worker servers: a request runs past the worker timeout (30 seconds by default in Gunicorn), the master kills the worker, and nginx reports a 502 for that request. Raising nginx timeouts does not help here; the limit is in the app server.
On AWS, an Application Load Balancer returns 502 when the target closes the connection or sends a malformed response, and also when the target's keep-alive timeout is shorter than the load balancer's idle timeout, so the target closes connections the balancer still considers open.
How to debug it
- Read the proxy's error log for the matching request; the message names the failure (refused, reset, closed, invalid header).
- From the proxy host, call the upstream directly, for example
curl -v http://127.0.0.1:8000/, using the exact address and port in the proxy config. - Check that the app is running and has not been restarted by a crash loop or an out-of-memory kill (
dmesg,journalctl, container restart counts). - Look for app-server worker timeouts or crashes at the same timestamp in the upstream's logs.
- With containers, confirm the app listens on
0.0.0.0rather than127.0.0.1inside the container, and that the proxy uses the right host and port. - If the upstream returns very large headers (big cookies), raise
proxy_buffer_size; nginx logsupstream sent too big headerin that case.
Gotchas
- Cloudflare shows its own 502 page for origin failures, but most origin problems appear as Cloudflare's 520-526 codes instead.
- A 502 that appears only during deploys usually means the proxy sends traffic to instances that are still starting or already shutting down; add a readiness check and graceful shutdown.
- TLS to the upstream can fail too: with
proxy_pass https://..., a certificate or SNI mismatch produces 502. Checkproxy_ssl_server_name on;.
Related explainers
- 504 Gateway TimeoutA 504 means a proxy waited too long for the app behind it. Which timeout fired (nginx proxy_read_timeout,...
- 503 Service Unavailable503 means the server is temporarily unable to handle requests. Common sources: no healthy backends, nginx...
- 500 Internal Server ErrorA 500 is the server's generic failure code, usually an unhandled exception. Where to find the real error...
- 499 Client Closed Request (nginx)499 is an nginx log code: the client hung up before the response was sent. What causes it, why the client...