A config that doesn't error is not a config that works.
logrotate misconfigurations don't fail loudly. They fail silently. You only find out when /var/log is 100% full and something crashed.
The copytruncate race condition
The copytruncate directive exists because some processes don't respond to SIGHUP. Instead of telling the process to reopen its log, logrotate copies the file and truncates it in place.
Sounds reasonable. The problem is the gap between "copy" and "truncate." On a busy nginx server writing hundreds of lines per second, you're going to drop log entries. On a quieter system you might silently duplicate them.
/var/log/nginx/access.log {
daily
rotate 7
compress
copytruncate # this is the problem on high-throughput services
}
The fix is the postrotate approach:
/var/log/nginx/access.log {
daily
rotate 7
compress
postrotate
nginx -s reload
endscript
}
Your process handles the log reopen cleanly. No race, no dropped lines.
The silent-failure trap
logrotate returning 0 doesn't mean anything rotated. A missing file, wrong path, permission issue, or a config directive that doesn't apply — all of these produce a clean exit code.
/usr/sbin/logrotate -d /etc/logrotate.conf
The -d flag runs logrotate in debug mode. It prints what it would do without doing it. Run this before shipping any config change.
One thing to know: -d still reads your actual state. If a file was already rotated today, the debug run won't show you what happens on a fresh invocation. Run it right after touching the config, not after the daily run already fired.
A quick sanity check for any config
/usr/sbin/logrotate -d /etc/logrotate.d/your-app 2>&1 | head -30
Look for:
- "renaming" lines — confirms it found the target files
- "empty log" warnings — the source file is missing or zero-size
- "error" strings — permission or path issues
If you see "log needs rotating" but no "renaming", you hit the maxsize/rotations-per-day guard and the file was skipped intentionally.
What actually fills disks in practice
The most common real-world cause isn't a clever attack or misbehaving application. It's a logrotate config that never had compress on a high-volume file, and nobody noticed for three months because the disk monitor didn't alert on /var.
The second most common: a process that held a file descriptor open after logrotate moved the file. The rotated file stays on disk until the process restarts. lsof +L1 catches this quickly.
That's it. No magic. Check your postrotate hooks, run logrotate -d before shipping configs, and add lsof +L1 to your disk-full checklist.
Top comments (0)