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

> A 502 means your proxy is up but whatever sits behind it isn't answering properly. How to find which hop failed, with curl and log commands.

Published: 2026-07-27 | Updated: 2026-08-09 | Canonical: https://yoping.me/guides/502-bad-gateway

A 502 is good news wearing a scary costume: something in your stack is
alive and talking - that's who sent the 502 - but the thing *behind* it
returned garbage or nothing. Your job is to find the first hop that stops
answering.

## What does 502 Bad Gateway actually mean?

A server acting as a gateway - nginx, Apache, a load balancer, a CDN -
forwarded your request upstream and got an invalid response back: a
connection refused, a reset, a malformed reply, or silence. The proxy is
fine. The upstream is not.

## Which layer is sending the 502?

Read the error page itself first. "nginx" branding means your nginx
reached a dead upstream. A Cloudflare-styled 502 means Cloudflare
couldn't get a sane answer from your origin - which may itself be an
nginx with its own dead upstream. Then test hops directly:

```
# Through the front door
curl -sI https://example.com

# Straight to your origin, bypassing the CDN
curl -sI --resolve example.com:443:203.0.113.7 https://example.com

# From the origin box: is the app process even listening?
curl -sI http://127.0.0.1:3000
```

Wherever the answer changes from 502 to something else, you've crossed
the broken link.

## Why do upstreams stop answering?

In rough order of likelihood:

- **The app process crashed or was never restarted** after a deploy.
  `systemctl status myapp` or `docker ps` settles it in seconds.
- **The app is up but overwhelmed** - connections accepted, replies too
  slow or reset. Often shows up as a mix of 502s and 504s.
- **Port or socket mismatch** - the proxy points at `:3000`, the app now
  listens on `:8080`, or a unix socket path changed.
- **The upstream's TLS is broken** and the proxy refuses the handshake.

Your proxy's error log names the culprit precisely:

```
tail -f /var/log/nginx/error.log
# "connect() failed (111: Connection refused) while connecting to upstream"
```

Connection refused means nothing is listening. Timeouts point to
[504 territory](/guides/504-gateway-timeout).

## How do I stop the next 502 from being a surprise?

A 502 is exactly the failure your own browser hides from you - the site
worked when you deployed, died an hour later, and the first report came
from a user. An external check catches it from outside your network:
YoPingMe requests your site from two regions you choose, and pages you
by email, webhook, or Slack only when both agree it's down. [Ten monitors are
free](https://app.yoping.me/signup), and the first check runs while you sign
up.
