Nginx writes two logs by default: the access log at /var/log/nginx/access.log and the error log at /var/log/nginx/error.log. These paths are identical on Ubuntu, Debian, RHEL, CentOS, and Fedora when nginx is installed from the distro or official nginx package. The locations are controlled by the access_log and error_log directives in /etc/nginx/nginx.conf, and individual server {} blocks frequently override them with per-site files such as /var/log/nginx/example.com.access.log.
Quick Reference: Nginx Log File Paths
| Platform / Install method | Access log | Error log |
|---|---|---|
| Ubuntu / Debian (apt) | /var/log/nginx/access.log | /var/log/nginx/error.log |
| RHEL / CentOS / Fedora (yum/dnf) | /var/log/nginx/access.log | /var/log/nginx/error.log |
| nginx.org official repo | /var/log/nginx/access.log | /var/log/nginx/error.log |
| Source build (default prefix) | /usr/local/nginx/logs/access.log | /usr/local/nginx/logs/error.log |
| Homebrew (macOS, Intel) | /usr/local/var/log/nginx/access.log | /usr/local/var/log/nginx/error.log |
| Homebrew (macOS, Apple Silicon) | /opt/homebrew/var/log/nginx/access.log | /opt/homebrew/var/log/nginx/error.log |
| Docker (official image) | stdout (docker logs) | stderr (docker logs) |
| Per-site (common override) | /var/log/nginx/<site>.access.log | /var/log/nginx/<site>.error.log |
The startup error log — written before nginx reads its config — is also compiled in at build time. Check it with nginx -V 2>&1 | tr ' ' '\n' | grep error-log.
How to View and Tail Nginx Logs
Follow the live access log:
sudo tail -f /var/log/nginx/access.log
Follow the error log and access log together:
sudo tail -f /var/log/nginx/error.log /var/log/nginx/access.log
Find the last 50 errors:
sudo tail -n 50 /var/log/nginx/error.log
Filter the access log for a specific status code (502 Bad Gateway here):
sudo grep ' 502 ' /var/log/nginx/access.log
Count requests per IP address (top 10 talkers):
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
Inside Docker, logs go to the container's stdout/stderr:
docker logs -f <container>
docker logs --tail 100 <container>
Finding the Exact Path When It Varies
Never guess. Have nginx tell you the resolved paths:
sudo nginx -T 2>&1 | grep -E 'access_log|error_log'
nginx -T dumps the fully merged configuration including every included file, so you see every log directive across all server blocks. Lines reading access_log off; confirm logging is intentionally disabled for that scope.
Ubuntu / Debian Detail
The package ships a global error_log /var/log/nginx/error.log; and access_log /var/log/nginx/access.log; in /etc/nginx/nginx.conf. Site configs live in /etc/nginx/sites-available/ and typically add their own per-host log files. To change a path, edit the directive and reload:
sudo nano /etc/nginx/nginx.conf
sudo nginx -t && sudo systemctl reload nginx
RHEL / CentOS / Fedora Detail
Paths match Debian, but SELinux governs where nginx may write. If you move logs outside /var/log/nginx/, restore the correct context or nginx will be denied:
sudo semanage fcontext -a -t httpd_log_t "/data/logs(/.*)?"
sudo restorecon -Rv /data/logs
Config lives in /etc/nginx/nginx.conf with extra files under /etc/nginx/conf.d/.
Docker Detail
The Dockerfile for the official image contains ln -sf /dev/stdout /var/log/nginx/access.log and ln -sf /dev/stderr /var/log/nginx/error.log. That is why docker logs works out of the box and why there are no files to tail inside the container. To persist real files, mount a volume and replace the symlinks:
docker run -v /host/nginx-logs:/var/log/nginx mynginx
Confirm where a running container sends its logs:
docker inspect --format '{{.LogPath}}' <container>
Changing the Log Location and Format
Set a named log format and direct it to a custom file in nginx.conf or a server block:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/nginx/custom.access.log main;
error_log /var/log/nginx/custom.error.log warn;
The error log's second argument is the level: debug, info, notice, warn, error, crit, alert, or emerg. Lower levels produce more output.
Log Rotation
Logrotate handles nginx on package installs. The config is /etc/logrotate.d/nginx:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
The postrotate USR1 signal tells nginx to reopen its log files after rotation so it keeps writing to the fresh file rather than the renamed one. Test rotation without waiting a day:
sudo logrotate -f /etc/logrotate.d/nginx
Common Errors You'll Find in Nginx Logs
connect() failed (111: Connection refused) while connecting to upstream— the backend (PHP-FPM, app server) is down or listening on a different port; surfaces to clients as 502.upstream timed out (110: Connection timed out)— backend took longer thanproxy_read_timeout; raise the timeout or fix the slow backend, results in 504.open() "/var/www/html/x" failed (13: Permission denied)— nginx's worker user (www-dataornginx) cannot read the file; fix ownership or permissions.directory index of "/var/www/html/" is forbidden— no index file and autoindex off; serves a 403.SSL_do_handshake() failed— TLS negotiation problem, often a client using an unsupported protocol or a bad certificate chain.worker_connections are not enough— the worker hit its connection limit; raiseworker_connectionsin theevents {}block.
Troubleshooting: Logs Missing or Empty
- Logging disabled —
access_log off;in a server or location block silences requests served there. Confirm withnginx -T. - Wrong file — the request is matched by a different server block that writes to its own per-site log. Match the
server_nameandlistento find the right file. - Permissions — your user cannot read
/var/log/nginx/. Usesudo, or add yourself to theadmgroup on Debian. - Errors before config load — syntax errors and startup failures go to the compiled-in default log or to the systemd journal:
journalctl -u nginx. - Docker — there are no files inside the official image; use
docker logs. Files only exist if you removed the stdout/stderr symlinks. - Not reloaded — after editing a path, run
sudo nginx -t && sudo systemctl reload nginx; without a reload nginx keeps writing to the old file.