首页 > Technology > 正文

How to Fix 502 Bad Gateway on Nginx (A Real Troubleshooting Walkthrough)

fenij 2026-08-05 5 Technology

A 502 Bad Gateway from Nginx means one thing: Nginx reached out to your backend and got back something it could not use. Nginx itself is fine. The application behind it — PHP-FPM, Node, Gunicorn, whatever you run — either refused the connection, died mid-request, or sent back a malformed response. The error page tells you nothing useful, so stop staring at it and go read the log.

Start with the error log

Everything you need is usually in the first line you find here:

tail -f /var/log/nginx/error.log

Reload the broken page in another tab and watch what shows up. Four messages cover most cases:

  • connect() failed (111: Connection refused) — the backend is not listening.
  • connect() to unix:/run/php/php8.2-fpm.sock failed (13: Permission denied) — socket permissions.
  • upstream prematurely closed connection while reading response header — the backend process died or was killed.
  • upstream sent too big header while reading response header — buffer sizes are too small.

Each one points somewhere different. Match yours before changing any config.

Case 1: the backend is not running

Check the service and the port in one go:

systemctl status php8.2-fpm
ss -lntp | grep -E '9000|3000|8000'
ls -l /run/php/php8.2-fpm.sock

If the unit is dead, start it and read why it stopped:

systemctl start php8.2-fpm
journalctl -u php8.2-fpm -n 50 --no-pager

A syntax error in a PHP config file or a bad pool definition will keep it from coming back. Fix that first — restarting in a loop just wastes time.

Also make sure the address in your Nginx config matches reality. If fastcgi_pass unix:/run/php/php7.4-fpm.sock; is still there after a PHP 8 upgrade, you get a 502 every single request.

Case 2: PHP-FPM ran out of children

Under traffic this is the usual culprit. Look in the FPM log:

grep 'max_children' /var/log/php8.2-fpm.log

A line reading server reached pm.max_children setting (5), consider raising it means requests queued up until Nginx gave up. Edit /etc/php/8.2/fpm/pool.d/www.conf:

pm = dynamic
pm.max_children = 30
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 12
pm.max_requests = 500

Do not pick 30 because I wrote 30. Measure your average PHP process size with ps -ylC php-fpm8.2 --sort:rss, then divide the RAM you can spare by that number. Setting max_children higher than your memory allows trades 502s for OOM kills, which is worse.

Reload after editing:

php-fpm8.2 -t && systemctl reload php8.2-fpm

Case 3: header or buffer overflow

Sites with large cookies or long redirect chains hit this. Add to the server or location block:

fastcgi_buffer_size 32k;
fastcgi_buffers 8 32k;
fastcgi_busy_buffers_size 64k;

For a proxied app use the proxy_ equivalents instead. Test and reload:

nginx -t && systemctl reload nginx

Case 4: the process is getting killed

If the log says the upstream closed early and the service keeps restarting on its own, check the kernel:

dmesg -T | grep -i 'killed process'

An OOM kill means the box is out of memory. Lower pm.max_children, add swap, or move the database off the same server. A PHP script hitting memory_limit can produce the same symptom, so raise that in php.ini if a specific page is the only one failing.

Case 5: socket permissions

Nginx runs as www-data on Debian and nginx on RHEL. The FPM socket has to be readable by whichever user yours is. In www.conf:

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

On RHEL with SELinux enforcing, add:

setsebool -P httpd_can_network_connect 1

Quick checklist

Read the error log. Confirm the backend is listening on the exact address Nginx points to. Check for max_children warnings. Bump buffers if headers are too big. Look for OOM kills. In my experience, roughly nine out of ten 502s are one of those five.

FAQ

Is a 502 different from a 504?
Yes. A 504 means the backend accepted the connection but did not answer in time, so you tune fastcgi_read_timeout. A 502 means the answer never came or came back broken. Different fixes, so read the status code carefully.

Why does the 502 only appear sometimes?
Intermittent 502s almost always come from resource exhaustion under load — max_children, database connections, or memory. Reproduce it with ab -n 500 -c 50 https://yoursite/ while tailing both logs.

Can a firewall cause a 502?
It can, when Nginx and the app run on separate hosts. Test the path with curl -v http://10.0.0.5:8000/ from the Nginx box. If curl hangs or gets refused, fix the firewall rule before touching Nginx.

Hit a 502 message that does not match anything above? Drop the exact error log line in the comments at fenij.com and I will help you read it.