A 502 is Nginx telling you that it asked something else to produce the page and got an answer it could not use. Nginx itself is running - if it were not you would see nothing at all - so the fault is behind it, almost always in PHP.
Tell which of the four it is
Read the error log first. It names the cause in one line, and every minute spent guessing is a minute not spent reading it.
tail -50 /var/log/nginx/error.log
- connect() failed (111: Connection refused) — PHP-FPM is not running.
- upstream timed out — PHP is running but took longer than the timeout.
- recv() failed (104: Connection reset by peer) — the PHP worker died mid-request, usually out of memory.
- no live upstreams — the pool has no workers left to answer.
PHP-FPM is not running
- Check it — systemctl status php8.3-fpm — a stopped service says so in the first line.
- Start it — systemctl start php8.3-fpm
- Find out why it stopped — journalctl -u php8.3-fpm --since "1 hour ago" — a bad line in a pool config stops it at start-up and it will stop again.
php-fpm8.3 -t. It validates the pool files and names the line it does not like.PHP is too slow for the timeout
The default gives PHP 60 seconds. A slow import or an external API that stopped answering will pass that, and Nginx returns 502 rather than waiting forever.
location ~ \.php$ {
fastcgi_read_timeout 300;
}
The worker died
A request that exceeds memory_limit kills its worker, and Nginx sees the connection reset. The PHP error log names the file and the line.
grep -i "allowed memory size" /var/log/php8.3-fpm.log | tail
The pool has no workers
Every worker is busy, so a new request has nowhere to go. That is a capacity problem, and the honest fix is either fewer slow requests or more workers - but more workers on the same RAM only moves the failure.
pm.max_children = 20\npm.max_requests = 500