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.

Steps to configure log rotation for Nginx:

  1. Locate the logrotate configuration for Nginx.
    $ ls -la /etc/logrotate.d/nginx
    -rw-r--r-- 1 root root 356 Dec 14 09:40 /etc/logrotate.d/nginx
  2. 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:52:  access_log /var/log/nginx/access.log;
    /etc/nginx/nginx.conf:53:  error_log /var/log/nginx/error.log warn;

    Custom access_log or error_log paths require updating the logrotate glob (for example, changing /var/log/nginx/*.log).

  3. Review or create a rotation policy that fits the environment.
    /var/log/nginx/*.log {
        daily
        rotate 14
        compress
        delaycompress
        missingok
        notifempty
        sharedscripts
        postrotate
            if [ -s /run/nginx.pid ]; then
                kill -USR1 $(cat /run/nginx.pid)
            elif [ -s /var/run/nginx.pid ]; then
                kill -USR1 $(cat /var/run/nginx.pid)
            fi
        endscript
    }

    Nginx reopens logs on the USR1 signal, so the postrotate block prevents continued writes to the rotated file. Add a create line if new logs are not created after rotation. Set the user/group to match the deployment (common values include www-data or nginx). Avoid copytruncate on busy servers, since it can drop log lines during truncation.

  4. Test the rotation configuration in debug mode.
    $ sudo logrotate -d /etc/logrotate.d/nginx
    reading config file /etc/logrotate.d/nginx
    Reading state from file: /var/lib/logrotate/status
    Allocating hash table for state file, size 64 entries
    
    Handling 1 logs
    
    rotating pattern: /var/log/nginx/*.log  after 1 days (14 rotations)
    empty log files are not rotated, old logs are removed
    considering log /var/log/nginx/access.log
      log needs rotating
    considering log /var/log/nginx/error.log
      log needs rotating
    ##### snipped #####
  5. Force a rotation to validate the policy end-to-end.
    $ sudo logrotate -vf /etc/logrotate.d/nginx
    reading config file /etc/logrotate.d/nginx
    ##### snipped #####
    rotating pattern: /var/log/nginx/*.log  forced from command line (14 rotations)
    renaming /var/log/nginx/access.log to /var/log/nginx/access.log.1
    renaming /var/log/nginx/error.log to /var/log/nginx/error.log.1
    running postrotate script
    ##### snipped #####

    Force rotation changes files immediately, so run it during a maintenance window on busy servers.

  6. List the rotated log files to confirm retention/compression behavior.
    $ ls -lh /var/log/nginx
    total 140M
    -rw-r----- 1 root adm  12M Dec 14 09:41 access.log
    -rw-r----- 1 root adm  98M Dec 14 09:40 access.log.1
    -rw-r----- 1 root adm  14M Dec 13 09:40 access.log.2.gz
    -rw-r----- 1 root adm  2.1M Dec 14 09:41 error.log
    -rw-r----- 1 root adm  5.8M Dec 14 09:40 error.log.1
    ##### snipped #####
  7. Generate a request to create a new access log entry.
    $ curl -I http://127.0.0.1/
    HTTP/1.1 200 OK
    Server: nginx
    Date: Sun, 14 Dec 2025 09:41:35 GMT
    Content-Type: text/html
    Content-Length: 612
    Connection: keep-alive
    ##### snipped #####
  8. Confirm that Nginx is writing to the active log files.
    $ sudo tail -n 5 /var/log/nginx/access.log
    127.0.0.1 - - [14/Dec/2025:09:41:35 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/8.4.0"
    ##### snipped #####
Discuss the article:

Comment anonymously. Login not required.