Why bother with Nginx logs
Nginx logs are the first place to check for any problem: a slow site, a 502 error, a suspicious traffic spike. By default the server writes two files: /var/log/nginx/access.log with every request and /var/log/nginx/error.log with worker and backend errors.
Without configuring the format and rotation, logs quickly turn into a useless pile: the disk fills up, and finding the right line among millions of entries becomes impossible.
The access_log format: what the fields mean
The standard combined format is set in nginx.conf, but it is worth extending with a response time field:
log_format extended '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct=$upstream_connect_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log extended;| Variable | What it contains |
|---|---|
| $remote_addr | Client IP address |
| $status | Response code: 200, 404, 502, and so on |
| $request_time | Full request processing time on Nginx |
| $upstream_response_time | Response time of PHP-FPM or another backend |
The rt field is the most useful for diagnostics: if request_time is large while upstream_response_time is small, Nginx itself or the network is slow, not the application.
How to configure log rotation
On Ubuntu and Debian, Nginx log rotation is usually handled by logrotate through the /etc/logrotate.d/nginx configuration:
/var/log/nginx/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}The USR1 signal makes Nginx reopen its log files without restarting the workers — otherwise, after the file is renamed, logging continues into the deleted inode while the new file stays empty.
How to quickly find what you need in access.log
Common queries for parsing logs — no special tools needed, just grep and awk:
- all requests with code 502 for today:
grep " 502 " access.log - top 10 IP addresses by request count:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10 - requests slower than 2 seconds:
awk '$NF+0 > 2 {print}' access.log - request count by response code:
awk '{print $9}' access.log | sort | uniq -c
What to look for in error.log
The error.log file records worker problems: configuration errors, dropped connections to the backend, exceeded timeouts. The logging level is set by the error_log /var/log/nginx/error.log warn; directive — for production, the warn level is enough, debug is enabled only during diagnostics since it creates a huge volume of entries.
Lines like upstream timed out and connect() failed point to a backend problem, not to Nginx itself — a reason to check PHP-FPM or the proxy server.
Storage and analysis at scale
When there are several sites and servers, manually parsing logs over ssh stops working. Logs are worth shipping to a centralized store: syslog, Loki, or Elasticsearch, while keeping only the last 14 days on the server itself so the disk does not fill up.
Summary
A checklist for Nginx logs:
- extend log_format with the request_time and upstream_response_time fields
- configure logrotate with the USR1 signal to reopen files
- keep error_log at the warn level in production
- look for slow and failed requests with awk and grep before calling a developer
If codes 502 and 504 show up regularly in the logs, work through the causes separately in the article diagnosing 502 Bad Gateway and 504 Gateway Timeout, and for the PHP connection see configuring Nginx and PHP-FPM.