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.