Logrotate Isn't Rotating — Logs Grow Forever

Silent log growth fills disks at 3am. When rotation stops, the causes are almost always: config not in the search path, a status-file conflict, permissions on the log dir, or cron not running the job.

What you'll see

Root causes

Config isn't where logrotate looks

logrotate reads /etc/logrotate.conf plus /etc/logrotate.d/*. If your app's config lives in /opt/app/logrotate.conf, nothing includes it. Test: sudo logrotate -d /etc/logrotate.conf 2>&1 | grep -A5 <logfile>.

Status file / permissions problems

A stale /var/lib/logrotate/status line claiming the log was rotated today skips it. And if the app's user can't be su'd to (missing shell), postrotate reloads fail and rotation aborts.

Cron/anacron isn't running the daily job

logrotate runs from /etc/cron.daily. Check systemctl status cron and journalctl -u cron | grep logrotate — a disabled anacron on laptops/containers means daily jobs silently never run.

Fix it

  1. Dry-run with debug to see the decision log
    sudo logrotate -d /etc/logrotate.conf 2>&1 | tail -30   # -d = no changes, shows why each file rotates or not
  2. Force one rotation to validate the config end-to-end
    sudo logrotate -f /etc/logrotate.d/<yourapp>   # then verify the .1 file and that the app keeps writing to the fresh log
  3. Add a config for your app the standard way
    # /etc/logrotate.d/myapp:
    # /var/log/myapp/*.log { daily; rotate 14; compress; missingok; notifempty; copytruncate; su www-data www-data }
  4. If the app keeps writing to the rotated file — use copytruncate
    # 'copytruncate' avoids the postrotate reopen signal for apps that hold their fd forever

Field note

copytruncate can lose log lines written during the copy — acceptable for most app logs, not for audit logs. Containers usually have no cron: run logrotate as a sidecar/cron-job container, or ship logs to stdout and let the runtime rotate.

Common questions

Why does my app keep writing to the old (renamed) log file?

It holds the file descriptor; renaming doesn't change the fd. Either send a reopen signal in postrotate (kill -USR1 for nginx, copytruncate for apps that can't), or fix the app to reopen logs on demand.

logrotate -d says 'log does not need rotating' but it clearly does.

The status file tracks last rotation dates; if it claims today, rotation is skipped. Check /var/lib/logrotate/status (or /var/lib/logrotate.status on some distros) and run with -f once to force past it.

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.