What it means

111 is the Linux error ECONNREFUSED: the backend host answered the connection attempt with a reset because no process listens on that port. nginx returns 502 Bad Gateway to the client.

[error] 1234#1234: *12 connect() failed (111: Connection refused) while connecting to upstream, client: 203.0.113.7, server: example.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/"

With PHP-FPM, the upstream field reads fastcgi://127.0.0.1:9000.

Common causes

1. The app is not running. It crashed, a deploy failed, or it never started after a reboot, sometimes because another process held its port (the same 98: Address already in use that stops nginx from starting). Confirm:

systemctl status myapp
docker ps -a --filter "name=app"

2. It listens somewhere else. The app binds 127.0.0.1 while nginx connects to another IP, PHP-FPM listens on a socket while nginx targets port 9000, or localhost inside a container points at nginx itself. Confirm on the backend host:

sudo ss -ltnp | grep -E ":3000|:9000"
grep -R "^listen" /etc/php/*/fpm/pool.d/

3. A restart window. Requests arrive while the app restarts. The errors cluster at deploy times and stop on their own.

4. A stale IP in Docker. nginx resolves the hostname in proxy_pass once, at startup. After the app container is recreated with a new IP, nginx keeps connecting to the old one.

How to fix

  1. Run ss -ltnp on the backend host to see what actually listens, and on which address.
  2. If nothing does, start the app and read its logs for why it exited.
  3. Make proxy_pass or fastcgi_pass match the listen address exactly: same IP or service name, same port, or the same socket path.
  4. For Docker IP changes, reload nginx after recreating containers, or resolve at request time with resolver 127.0.0.11 valid=10s; and a variable in proxy_pass.
  5. For deploys, run two instances in the upstream block so nginx retries the other one (proxy_next_upstream error timeout is the default), and restart them one at a time.
  6. Test and reload: sudo nginx -t && sudo systemctl reload nginx.

Is it just you?

Confirm the 502 is visible from outside, and from which regions, with Is my site down?.

Get alerted next time

  • A TCP port monitor on the app's port, when it is reachable from outside, fails the moment nothing listens there anymore.
  • An HTTP monitor on the public URL fails when nginx answers 502 instead of the status code you expect.
  • Each failure is rechecked from your other regions before an outage opens, so a two-second restart does not page anyone.