502 🌐 HTTP

HTTP 502 Bad Gateway

A proxy or gateway (Nginx, load balancer, CDN) got an invalid response — or no response — from the upstream server behind it.

Meaning

With 502 the proxy is working; the app server behind it is not. Typical setups: Nginx → PHP-FPM, Nginx → Node/Gunicorn, ALB → EC2/containers, Cloudflare → origin. The upstream crashed, isn’t listening on the expected port/socket, or closed the connection mid-response.

Common causes

  • Upstream app is down or crashed (PHP-FPM, Node, Gunicorn, container)
  • Wrong upstream address, port or Unix socket path in proxy config
  • Upstream process killed by OOM or restarted during the request
  • Socket permission mismatch between Nginx and PHP-FPM
  • Upstream response headers too large for proxy buffers
  • Firewall/security group blocking proxy → upstream

⚡ Quick fix

  1. Check that the upstream service is running (systemctl status php8.2-fpm, pm2 status, docker ps)
  2. Verify the proxy_pass / fastcgi_pass address matches where the app listens
  3. Read the proxy error log — it names the upstream error (connection refused, reset, prematurely closed)
  4. Restart the upstream service and watch its logs

Detailed fix by platform

Nginx

  1. "connect() failed (111: Connection refused)" → upstream not listening; "(13: Permission denied) while connecting to upstream" → socket permissions or SELinux.
  2. Match the PHP-FPM socket:
    nginx
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;   # must match listen = in www.conf
    }
  3. "upstream sent too big header" → raise proxy_buffer_size 16k; proxy_buffers 4 32k; (or fastcgi_ equivalents).

PHP

  1. Check listen, listen.owner and listen.group in /etc/php/8.2/fpm/pool.d/www.conf; look for "server reached pm.max_children" in the FPM log.

Node.js

  1. Ensure the app listens on the port Nginx proxies to and on 0.0.0.0 inside containers; check for crashes in pm2 logs.

AWS

  1. ALB 502: check target health, that targets respond with valid HTTP, and that app keep-alive timeout is longer than the ALB idle timeout (60s).

Cloudflare

  1. Cloudflare-branded 502 means the origin returned an invalid response; check origin logs, or see 520–526 for specific edge errors.

Code examples

Quick upstream checks

bash
sudo tail -n 30 /var/log/nginx/error.log
sudo ss -ltnp | grep -E ':(3000|8000|9000)'
ls -l /run/php/
curl -I http://127.0.0.1:3000/   # hit the upstream directly, bypassing Nginx

How to diagnose

  1. Proxy log — What upstream error does Nginx/LB report?
  2. Upstream process — Running? Recently restarted or OOM-killed?
  3. Address — Port/socket in config matches where the app listens?
  4. Direct test — Does the upstream answer when called directly?
  5. Network — Firewall/security groups between proxy and upstream?

🧠 Still stuck? Analyze your error

Paste the full message, response headers or stack trace — we'll detect the platform and point to the most likely cause.