Most time lost to a fault is spent reading the wrong log. Each one answers a different question, and picking the right file first usually makes the rest quick.
- /var/log/nginx/error.log - the web server could not do its job: upstream refused, permission denied, file not found.
- /var/log/nginx/access.log - what was requested and what was returned. This is where you find WHEN.
- /var/log/php8.3-fpm.log - workers dying, pool problems.
- the application log - your own code. The stack trace lives here and nowhere else.
Watch it while you reproduce
tail -f /var/log/nginx/error.log
Leave that running, load the broken page, and read what appears. That is the single most effective debugging step there is, and it takes ten seconds.
Find the shape of the problem
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
grep ' 500 ' /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head
The first shows the mix of status codes. The second names the URLs that are failing, ordered by how often - and one URL is usually most of them.
Narrow by time
sed -n '/04\/Sep\/2026:14:0/,/04\/Sep\/2026:14:2/p' access.log | grep ' 50'
The first occurrence is the one that matters
Read the FIRST error in a burst, not the last. The later ones are usually consequences - a queue backing up, a connection pool exhausting - and fixing a consequence changes nothing.
If the log is empty when something clearly failed, the request never reached that layer. Move one layer out: no PHP error means Nginx refused it; no Nginx entry means it never arrived.