# Fix Nginx Log Rotation Permission Denied After Logrotate

Your Nginx logs stop rotating, or worse, after logrotate runs, Nginx cannot write to the new log file. You find errors like these:

bash
error: error renaming /var/log/nginx/access.log to /var/log/nginx/access.log.1: Permission denied
bash
2026/04/08 08:00:01 [alert] 1234#1234: open() "/var/log/nginx/access.log" failed (13: Permission denied)

The new log files are owned by root:root, but the Nginx worker process runs as www-data and cannot write to them.

The Root Cause

Logrotate creates new files with ownership determined by the create directive in the logrotate configuration. If the directive specifies root:root or is missing entirely, the new files are not writable by the Nginx worker process.

Fixing the Logrotate Configuration

Edit /etc/logrotate.d/nginx:

bash
/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
}

The critical line is:

bash
create 0640 www-data adm

This creates new log files with permission 0640 (owner read/write, group read), owned by www-data (the user Nginx workers run as), group adm (allows log analysis tools to read).

Verifying Nginx Worker User

Confirm which user your Nginx worker processes run as:

bash
grep "^user" /etc/nginx/nginx.conf
# Default on Debian/Ubuntu: user www-data;
# Default on RHEL/CentOS: user nginx;

Adjust the logrotate create directive to match.

Manual Test of Log Rotation

After fixing the configuration, test it:

bash
sudo logrotate -f /etc/logrotate.d/nginx
ls -la /var/log/nginx/

You should see:

bash
-rw-r----- 1 www-data adm  0 Apr  8 10:00 access.log
-rw-r----- 1 www-data adm  0 Apr  8 10:00 error.log
-rw-r----- 1 www-data adm  54321 Apr  8 09:59 access.log.1

Then verify Nginx can still write:

bash
curl -s http://localhost/ > /dev/null
tail -1 /var/log/nginx/access.log

Fixing Existing Permissions

If current log files already have wrong ownership, fix them:

bash
sudo chown www-data:adm /var/log/nginx/*.log
sudo chmod 0640 /var/log/nginx/*.log

Alternative: Using copytruncate

If the postrotate script fails to signal Nginx properly, use copytruncate:

bash
/var/log/nginx/*.log {
    daily
    copytruncate
    rotate 14
    compress
    delaycompress
    notifempty
}

This copies the log file and then truncates the original, so Nginx never needs to reopen a new file. However, there is a small window where log entries can be lost between the copy and the truncate. For production systems, the create + postrotate approach is preferred.

Systemd Journal Integration

On modern systems, consider sending Nginx logs to journald instead of files:

nginx
error_log stderr error;
access_log /dev/stdout;

Then use journalctl for log management, which handles rotation automatically:

bash
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --vacuum-size=100M

This eliminates logrotate permission issues entirely, though it requires adapting your log analysis pipeline.