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; this is the log line behind nginx 502 Bad Gateway, and reading it tells you whether the upstream refused, timed out, or died mid-response.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. Both this and the permission error above reach the browser as 403 Forbidden from nginx, and only the error log distinguishes the two causes.client intended to send too large body— the upload exceededclient_max_body_size, which nginx rejects as 413 Request Entity Too Large before the request ever reaches your application.SSL_do_handshake() failed— TLS negotiation problem. When no shared protocol version or cipher suite can be agreed, the client side of the same failure is ERR_SSL_VERSION_OR_CIPHER_MISMATCH.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.