Rotating Nginx access and error logs keeps /var/log from growing until the filesystem fills, while preserving enough history to troubleshoot outages, investigate suspicious traffic, and compare performance over time.
Most Linux distributions rely on logrotate to rename and optionally compress log files on a schedule (often via cron or a systemd timer). Because Nginx keeps log files open, rotation must be followed by a reopen signal so the master process closes old file descriptors and resumes writing to the active log paths.
Retention, rotation frequency, and compression settings should match traffic volume and incident-response needs. Incorrect file patterns, permissions, or ownership can leave logs unrotated or stop logging entirely after a rotation, so a dry-run plus a one-time forced rotation provides a safe validation path before relying on the policy in production.
Related: How to secure Nginx web server
Related: How to locate Nginx access and error log files
Steps to configure log rotation for Nginx:
- Locate the logrotate configuration for Nginx.
$ ls -la /etc/logrotate.d/nginx -rw-r--r-- 1 root root 329 Nov 30 2023 /etc/logrotate.d/nginx
- Confirm the Nginx log file paths matched by the rotation rule.
$ sudo grep -R --line-number -E '^[[:space:]]*(access_log|error_log)[[:space:]]' /etc/nginx/nginx.conf /etc/nginx/conf.d /etc/nginx/sites-enabled 2>/dev/null /etc/nginx/nginx.conf:4:error_log /var/log/nginx/error.log; /etc/nginx/nginx.conf:40: access_log /var/log/nginx/access.log;
Custom access_log or error_log paths require updating the logrotate glob (for example, changing /var/log/nginx/*.log).
- Review or create a rotation policy that fits the environment.
/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts prerotate if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ run-parts /etc/logrotate.d/httpd-prerotate; \ fi \ endscript postrotate invoke-rc.d nginx rotate >/dev/null 2>&1 endscript }Nginx must reopen logs after rotation. The default policy uses invoke-rc.d nginx rotate to signal the master process; if you customize this file, keep an equivalent reopen command and a create line with the correct user/group (commonly www-data or nginx). Avoid copytruncate on busy servers, since it can drop log lines during truncation.
- Test the rotation configuration in debug mode.
$ sudo logrotate -d /etc/logrotate.d/nginx warning: logrotate in debug mode does nothing except printing debug messages! Consider using verbose mode (-v) instead if this is not what you want. reading config file /etc/logrotate.d/nginx Reading state from file: /var/lib/logrotate/status state file /var/lib/logrotate/status does not exist ##### snipped ##### considering log /var/log/nginx/access.log Creating new state Now: 2025-12-29 21:50 Last rotated at 2025-12-29 21:00 log does not need rotating (log has already been rotated) ##### snipped #####
- Force a rotation to validate the policy end-to-end.
$ sudo logrotate -vf /etc/logrotate.d/nginx reading config file /etc/logrotate.d/nginx Creating stub state file: /var/lib/logrotate/status acquired lock on state file /var/lib/logrotate/statusReading state from file: /var/lib/logrotate/status ##### snipped ##### rotating pattern: /var/log/nginx/*.log forced from command line (14 rotations) ##### snipped ##### running prerotate script renaming /var/log/nginx/access.log to /var/log/nginx/access.log.1 creating new /var/log/nginx/access.log mode = 0640 uid = 33 gid = 4 running postrotate script ##### snipped #####
Force rotation changes files immediately, so run it during a maintenance window on busy servers.
- List the rotated log files to confirm retention/compression behavior.
$ ls -lh /var/log/nginx total 4.0K -rw-r----- 1 www-data adm 0 Dec 29 21:50 access.log -rw-r----- 1 www-data adm 518 Dec 29 21:49 access.log.1 -rw-r----- 1 www-data adm 0 Dec 29 21:46 error.log
- Generate a request to create a new access log entry.
$ curl -I --silent http://127.0.0.1/ HTTP/1.1 200 OK Server: nginx/1.24.0 (Ubuntu) Date: Mon, 29 Dec 2025 21:50:42 GMT Content-Type: text/html Content-Length: 10671 Connection: keep-alive ETag: "6950cb18-29af" X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin ##### snipped #####
- Confirm that Nginx is writing to the active log files.
$ sudo tail -n 5 /var/log/nginx/access.log 127.0.0.1 - - [29/Dec/2025:21:51:55 +0000] "GET / HTTP/1.1" 200 10671 "-" "curl/8.5.0" 127.0.0.1 - - [29/Dec/2025:21:52:06 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/8.5.0" ##### snipped #####
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
