502 Bad Gateway: what it means and how to fix it

502 Bad Gateway means a proxy or gateway (nginx, Cloudflare, a load balancer, a tunnel) tried to reach the server behind it and got an invalid response or no response at all. The proxy itself is fine. The problem is the application it forwards to: it isn't running, it crashed mid-request, it's listening somewhere else, or it sent back something the proxy couldn't parse.

HTTP/1.1 502 Bad Gateway
Server: nginx
Content-Type: text/html

<html><head><title>502 Bad Gateway</title></head>
<body><center><h1>502 Bad Gateway</h1></center><hr><center>nginx</center></body></html>

Common causes

  • The upstream app isn't running. The process crashed, failed to start after a deploy, or was killed by the OOM killer.
  • Wrong host or port. proxy_pass, the load balancer target or the tunnel points at a port nothing listens on, or the app binds to 127.0.0.1 inside a container so the proxy can't reach it.
  • The app closed the connection. A worker was killed mid-request (Gunicorn's worker timeout is 30 seconds by default), or the app's keep-alive timeout is shorter than the proxy's, so the proxy reuses a connection the app already closed.
  • Scheme mismatch. The proxy speaks HTTPS to an app serving plain HTTP, or the reverse.
  • Invalid response. Oversized headers, a malformed status line, or a broken TLS handshake between proxy and origin.

How to fix it as a visitor

Reload after a minute. A 502 is often a short window during a deploy or restart. If it persists, try another network or check the site's status page. It's a server-side problem, so there's little else you can do.

How to fix it as a developer or ops

Start with the proxy's error log. It almost always names the cause.

WhereWhat you seeWhat it means
nginxconnect() failed (111: Connection refused) while connecting to upstreamNothing listens at the proxy_pass address. Start the app or fix the port.
nginxupstream prematurely closed connection while reading response headerThe app crashed or was killed mid-request. Check app logs and worker timeouts.
nginxno live upstreams while connecting to upstreamEvery server in the upstream block is marked failed.
Cloudflare502 Bad Gateway or Error 520/521The origin refused, reset or returned an invalid response. 521 means it refused the connection.
AWS ALB502 in access logs, with target_status_code logged as a dash (no response)The target closed the connection or sent a malformed response.

Specific fixes:

  1. Confirm the app answers locally: curl -v http://127.0.0.1:8000/ from the proxy host. If that fails, the problem isn't the proxy.
  2. Bind to the right interface. In Docker, the app must listen on 0.0.0.0, not 127.0.0.1, for another container to reach it.
  3. Line up keep-alive timeouts. Behind an AWS ALB (idle timeout 60 seconds by default), set the app's keep-alive timeout higher than the ALB's. Node.js defaults server.keepAliveTimeout to 5 seconds, a classic cause of intermittent ALB 502s.
  4. Check memory and restarts. dmesg | grep -i oom, kubectl describe pod, or your process manager's logs show whether the app keeps dying.

If the proxy waited for the app and gave up instead, that's a 504 Gateway Timeout, not a 502.

502 from a tunnel or local webhook forwarder

A 502 is the classic tunnel error. The tunnel reached your machine, but the local app it forwards to didn't answer. With relay connect --name my-app http://localhost:3000 or relay forward --bucket my-app http://localhost:3000/webhooks, a 502 or a timeout reported by the provider means the agent couldn't reach the destination. Check that:

  • the dev server is actually running and listening on that port (see localhost:3000 for "refused to connect" fixes);
  • the port in the command matches the one your app printed on startup;
  • you used http:// for a plain local server, not https://.

502s on a webhook endpoint

When a provider gets a 502 from your webhook endpoint, it counts as a failed delivery. Most providers retry, but their windows vary from days to minutes, and some never retry automatically. A bad deploy that leaves the app down for an hour can silently lose events.

The fix is to make sure the event is stored somewhere before your app has to be up. Webhook Relay durable retries persist each webhook first, then retry with exponential backoff for up to 30 days until your endpoint returns 2xx. Because delivery is at least once, make your handler idempotent.

When to return 502 from your own service

Return 502 only when your service is itself acting as a gateway and the upstream it called returned something invalid. If your own code failed, that's a 500 Internal Server Error. If you're deliberately refusing traffic during maintenance or overload, use 503 Service Unavailable.

Frequently asked questions

What does 502 Bad Gateway mean?

A 502 Bad Gateway means a server acting as a gateway or proxy, such as nginx, Cloudflare or a load balancer, tried to reach the server behind it and got an invalid response or none at all. The proxy is working; the application behind it is down, crashed, unreachable or sent back something the proxy couldn't use.

How do I fix 502 Bad Gateway in nginx?

Check the nginx error log first. Connection refused while connecting to upstream means the app isn't running or listens on a different port than proxy_pass. Upstream prematurely closed connection means the app crashed or was killed mid-request. Start or fix the app, make proxy_pass match its host and port, and reload nginx.

Is a 502 error my fault or the website's?

If you're visiting a site, it's almost always the website's problem. Reload after a minute, try another network, or check the site's status page. Clearing cookies or cache rarely helps, though it costs nothing to try.

Why does my tunnel or webhook forwarder return 502?

The tunnel reached your machine, but nothing answered on the local port it forwards to. The local app isn't running, crashed, listens on a different port, or expects plain HTTP while the tunnel is pointed at https. Start the app and check the port and scheme in the tunnel command.

Do webhook providers retry after a 502?

Most do, because 502 is a server error. But retry windows vary widely: some providers retry for days, some for minutes, and some never retry automatically. If the upstream stays down longer than the provider's window, the event is lost unless something in front of your endpoint stores it.