Access Log and Error Log
Introduction
Nginx writes two primary logs: access log records every request; error log records warnings and failures. Reading them is how you confirm traffic, debug 502s, and audit who hit your API. This chapter configures log paths, custom formats, and practical tail workflows alongside the Linux monitoring track.
Prerequisites
- Installing Nginx and Directory Layout
- Your First Virtual Host
- Optional: Linux monitoring and troubleshooting
Default Log Locations
| File | Content |
|---|---|
/var/log/nginx/access.log | Client IP, time, request, status, bytes |
/var/log/nginx/error.log | Startup errors, upstream failures, permission issues |
View live:
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.logCode explanation:
tail -ffollows new lines—standard during deploy verification- Use Ctrl+C to stop
access_log and error_log Directives
Per server or location:
server {
listen 80;
server_name api.example.com;
access_log /var/log/nginx/api.access.log;
error_log /var/log/nginx/api.error.log warn;
location / {
proxy_pass http://127.0.0.1:8080;
}
}Code explanation:
- Separate files per site simplify filtering on shared VPS hosts
error_log ... warn— levels:debug,info,notice,warn,error,crit
Disable access log for noisy health checks:
location /health {
access_log off;
proxy_pass http://127.0.0.1:8080/health;
}Default access Log Format
Typical line (combined-like):
203.0.113.50 - - [28/May/2026:10:15:00 +0000] "GET /api/users HTTP/1.1" 200 1234 "-" "curl/8.5.0"Fields: IP, remote user (often -), time, request line, status, body size, referer, user agent.
Custom log_format
In http block:
log_format api_log '$remote_addr - $request '
'$status $body_bytes_sent '
'rt=$request_time u=$upstream_response_time '
'"$http_user_agent"';
server {
access_log /var/log/nginx/api.access.log api_log;
}Code explanation:
$request_time— total request time$upstream_response_time— backend response time (useful for proxy tuning)
Reload after changing format:
sudo nginx -t && sudo systemctl reload nginxerror_log Levels in Practice
| Level | When to use |
|---|---|
warn | Production default—upstream errors, client mistakes |
error | Quieter—serious issues only |
debug | Deep troubleshooting—very verbose; short bursts only |
Temporary debug on one site:
error_log /var/log/nginx/api.error.log debug;Revert to warn after fixing—debug fills disks quickly.
Reading access Log for Status Codes
sudo awk '$9 == 502 {print}' /var/log/nginx/access.log | tail
sudo awk '$9 ~ /^5/ {print $7, $9}' /var/log/nginx/access.log | tail -20Code explanation:
$9is status code in default format—verify field index if you use custom format- Filter 5xx to spot server/proxy failures
Count hits per path:
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | headCommon error_log Messages
| Message | Meaning |
|---|---|
connect() failed (111: Connection refused) | Upstream not listening |
Permission denied | Nginx cannot read file or bind port |
open() "... failed (2: No such file) | Missing cert or root path |
upstream timed out | Backend slow; increase timeouts |
Cross-check with:
sudo journalctl -u nginx -n 50 --no-pagerLog Rotation
Distro packages often ship logrotate for /var/log/nginx/*.log. Manual rotate if needed:
sudo nginx -s reopenAfter moving/truncating logs, reopen tells Nginx to reopen file handles.
Privacy and Compliance
Access logs contain IPs and URLs—may include personal data under GDPR. Define retention policy, restrict log file permissions (640, root/adm), and avoid logging secrets in query strings.
FAQ
Can I log to syslog?
error_log syslog:server=...; — possible; files remain default on VPS.
JSON access logs?
Third-party modules or log shipper parsing combined format— or define custom format with quoted fields.
access_log off globally?
Not recommended—you lose audit trail. Disable only per health/static noise paths.
Why empty error.log?
No issues at warn level—good. Increase level temporarily when debugging.
Correlate with app logs?
Match timestamp + $request_id if you pass X-Request-Id to backend.
Disk full from logs?
Check rotation; reduce debug level; shrink retention in logrotate.