Home/Engineer/Troubleshooting/Fixing Nginx 502 Bad Gateway…
TroubleshootingIntermediateUbuntuDebianCentOSNginx502Bad Gateway

Fixing Nginx 502 Bad Gateway: Causes by Log Message and Inspection Order

Diagnose Nginx 502 Bad Gateway from error.log. Separate connection refused, PHP-FPM socket and permission issues, upstream connection closures, and oversized header errors, then walk through the fix and verification.

Contents
  1. 502 Bad Gateway: Log-Based Cause Lookup Table
  2. 1. Start by matching the request time and upstream address
  3. 2. Recover from a stopped app or address mismatch
  4. 3. Check the PHP-FPM socket and permissions
  5. 4. Distinguish app crashes, oversized response headers, and timeouts
  6. 5. Verify after the fix
  7. FAQ

A 502 Bad Gateway from Nginx means the proxy did not receive a valid response from the upstream. First, compare the error.log entries at the same timestamp with the actual proxy_pass target. What you need to fix depends on whether the app is down, the address is wrong, or socket access was denied.

The commands below assume a Linux Nginx reverse proxy. In containers, also check where you run the commands. 127.0.0.1 inside the Nginx container is the Nginx container itself, not another app container.

502 Bad Gateway: Log-Based Cause Lookup Table

Key string in error.logFirst cause to suspectNext check
connect() failed (111: Connection refused)App is not listening on that address/port; connection refusedss -ltnp, app service status, proxy_pass
connect() to unix:... failed (2: No such file or directory)Socket path mismatch or socket not created (PHP-FPM, etc.)Compare fastcgi_pass with FPM listen
connect() ... failed (13: Permission denied)Socket or parent-directory permissions, or security policyWorker user, path permissions, SELinux/AppArmor logs
upstream prematurely closed connectionApp closed the connection before sending headersApp exceptions, restarts, OOM records
upstream sent too big headerUpstream response headers larger than the bufferCookie/auth header size, proxy/FastCGI buffers
no live upstreamsNo selectable upstreamsUpstream config, preceding connection-failure logs

This table is a starting point for diagnosis. The same error can produce a different final status code depending on proxy retries and a front-end CDN. Nginx distinguishes connection errors, timeouts, and invalid response headers when deciding whether to retry an upstream. Nginx proxy_next_upstream documentation

1. Start by matching the request time and upstream address

Bash
# Run on the Nginx server: adjust the path to match the actual error_log setting.
sudo tail -n 80 /var/log/nginx/error.log
sudo nginx -T 2>&1 | grep -nE 'upstream|proxy_pass|fastcgi_pass|uwsgi_pass|error_log'
sudo ss -ltnp

nginx -T dumps the full configuration that will be applied. Strip any secrets from the config before sharing it externally. The upstream: address in the log must match the listening port.

For an HTTP upstream, send a request from the same server or container as Nginx. Replace the address below with your actual settings.

Bash
curl -sv --connect-timeout 3 --max-time 10 http://127.0.0.1:3000/health
  • Connection refused: check the app process, listen address, and port
  • App returns a normal response: check Nginx's target address, request path, and Host/TLS settings
  • Hangs after connecting: check app logs and DB/external API latency

A PHP-FPM FastCGI socket is not an HTTP server, so do not use this curl check as-is.

2. Recover from a stopped app or address mismatch

Bash
# Replace myapp with the actual service name
sudo systemctl status myapp --no-pager
sudo journalctl -u myapp --since '15 minutes ago' --no-pager
# If you run the app with PM2
pm2 status

If the service failed, fix the startup failure shown in the logs first. If the app listens on 3001 but Nginx connects to 3000, align one side with the actual design. In Docker Compose, check the service name on the same network and the container port.

3. Check the PHP-FPM socket and permissions

Bash
# Change the PHP version and paths below to match your install
sudo systemctl status php8.2-fpm --no-pager
sudo grep -nE '^listen([[:space:]]|\.)' /etc/php/8.2/fpm/pool.d/www.conf
ls -l /run/php/

Compare FPM listen with Nginx fastcgi_pass and confirm they point at the same socket. For permission errors, align FPM listen.owner, listen.group, and listen.mode with the Nginx worker user's access. Execute permission on parent directories is also required. PHP-FPM configuration documentation

If SELinux/AppArmor denial records exist, adjust the required access policy. Blindly applying chmod 777 to the socket or disabling the security module entirely is not a cause-appropriate fix.

4. Distinguish app crashes, oversized response headers, and timeouts

Bash
sudo journalctl -k --since '30 minutes ago' --no-pager | grep -iE 'oom|killed process'
free -h

Check whether the app restarted or was killed for memory at the same time as upstream prematurely closed connection. For oversized-header errors, inspect cookie or auth response size first, then adjust the buffers for that protocol.

Do not raise proxy_read_timeout just because you saw a 502. This value is the idle wait between successive reads from the upstream, not a limit on total request processing time. Timeouts are more often part of 504 diagnosis, so check the actual logs and responses together. Nginx proxy_read_timeout documentation

5. Verify after the fix

Bash
sudo nginx -t
# Run only after the syntax check succeeds
sudo systemctl reload nginx

Recheck both a direct request to the upstream and a request via the external domain. Confirm the HTTP status is back to the expected value and that the same error is not still accumulating in new logs. Do not treat the app's 401 or 404 as a failure by default; compare against the expected successful response for the path you tested.

FAQ

Will restarting Nginx fix it?

If the cause is a stopped app, a wrong upstream address, or socket permissions, restarting Nginx alone will not fix it. Fix the layer the logs point to first.

The app is healthy, but I only get 502 in Docker

A test inside the app container is not the same as a test from the Nginx container. Compare the service DNS name, network connectivity, the app's listen address, and the container port.

If you confirmed timeout logs, continue with Diagnosing 504 timeouts in nginx, ALB, and gunicorn.

#Nginx#502#Bad Gateway#Troubleshooting#upstream#PHP-FPM#proxy
Editorial note

AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us

Topic-related official docs (auto-linked · not per-claim sources)NGINX documentation ↗

Questions & answers

Ask a question about this guide. We'll review and reply.