How to Rotate Logs on a Schedule With logrotate and cron
Rotate logs on a schedule with logrotate: config syntax, daily or size rotation, copytruncate versus postrotate, testing with -d and how it is triggered.

An application writing to a log file will, given time, fill the disk. Logrotate is the standard answer: it keeps the last N files, compresses old ones and tells the program to start a new file. The common mistakes are rotating without telling the process, so it keeps writing to the renamed file, and expecting size limits to be enforced instantly. It continues the disk-space story in no space left on device, and the examples assume logrotate 3.21.
A stanza
/var/log/myapp/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
dateext
create 0640 myapp adm
sharedscripts
postrotate
systemctl kill -s HUP myapp.service 2>/dev/null || true
endscript
}
Save it as /etc/logrotate.d/myapp. daily with rotate 14 keeps two weeks. missingok and notifempty avoid errors and empty archives. delaycompress leaves the most recent rotated file uncompressed, which helps programs that still write to it briefly. create makes a fresh file with the given mode and owner. sharedscripts runs postrotate once for all files matched, not once per file. The file is plain text, so the block is marked as text.
Make the program reopen its file
systemctl kill -s HUP myapp.service
nginx -s reopen
kill -USR1 "$(cat /run/nginx.pid)"When logrotate renames app.log to app.log.1, the process still holds the open file and keeps writing into the renamed file. The program must be told to reopen its log path, usually with SIGHUP or a reload command. If it cannot be told, copytruncate copies the content aside and truncates the original in place; the program then keeps writing to the same file, with a risk of losing lines written between the copy and the truncate. Prefer postrotate when the program supports it. Programs that log to systemd's journal need no logrotate at all.
Test before trusting it
sudo logrotate -d /etc/logrotate.d/myapp
sudo logrotate -vf /etc/logrotate.d/myapp
ls -l /var/log/myapp/
cat /var/lib/logrotate/status | grep myapprotating pattern: /var/log/myapp/*.log after 1 days (14 rotations)
considering log /var/log/myapp/app.log
log needs rotating
renaming /var/log/myapp/app.log to /var/log/myapp/app.log-20261103
The debug flag prints what would happen without changing files, so syntax errors and wrong globs show up there. -f forces rotation even if it is not due. The state file records each log's last rotation, which explains why a file that "should" rotate did not. Check ownership and mode when the application runs as a non-root user; a mismatch between create and the application user causes permission errors after the first rotation.
What triggers it
systemctl list-timers logrotate.timer
cat /etc/cron.daily/logrotate 2>/dev/null | head -5On current distributions logrotate runs from a systemd timer once a day (or from /etc/cron.daily/logrotate on older ones). Everything that depends on the schedule moves at that frequency: hourly rotation needs an hourly trigger, for example a copy of the timer or a cron line calling logrotate /etc/logrotate.d/myapp each hour, with the hourly directive. A size 100M rule checks size only when logrotate runs. Compare with scheduling in cron schedules.
What rotation actually does to a file
Understanding the mechanics explains most surprises. The default method renames the active file and creates a new empty one at the original path. The process writing the log still holds a handle on the file object, not on the path, so after the rename its writes continue into the renamed file until it opens the path again. Rotation without a reopen step therefore produces a new empty log, a rotated file that keeps growing, and a monitoring dashboard that shows nothing happening. The postrotate signal exists to close that gap.
The copy-and-truncate alternative keeps the path and the handle intact. The file is copied, then truncated to zero length while the writer keeps going. It is the fallback for programs that cannot reopen their logs, and it has a window where lines written between the copy and the truncate are lost. For a verbose application, that can be thousands of lines. Use it only when nothing better is available, and note that if the writer did not open the file in append mode, a truncation leaves a sparse file with a hole where the old content was, because the next write goes to the old offset.
Retention, compression and disk planning
Pick the retention from two numbers: how long someone might want to look back, and how much space you can spend. Fourteen daily files at 200 MB each, compressed at about ten to one, cost under 400 MB, so there is little reason to be stingy. Increase the count or switch to weekly archives for logs that matter for audits. Check any legal or contractual retention requirement first, because it may demand a longer period, or a shorter one when the logs contain personal data.
Compression runs at the end of rotation and uses CPU and temporary disk space. For very large logs, it can briefly double the space in use, and a nearly full disk may fail the compression step and leave the uncompressed file. Leave headroom, and use compresscmd with zstd where available for a better speed and ratio than gzip. Date extensions with dateext make files easier to find than numeric suffixes that shift on every rotation.
Permissions and the non-root application
Most real-world rotation failures are permission problems. Logrotate runs as root and creates the new file with the owner and mode given in create. If the application runs as another user and the directory is owned by root, the program cannot create or reopen its log after rotation, and logs stop at midnight. Make the log directory writable by the application user, and set create to match. The su directive tells logrotate to rotate as a named user, which is needed when the directory is writable by a non-root group and logrotate refuses to operate on it for safety reasons.
Confirming that it works in production
Look at the result after the first scheduled run, not only at the dry run. Check that the new file is growing, that the previous one is the expected size and that the compressed archives open. Keep a monitoring check for the age of the newest line in each log, which catches the case where rotation succeeds and the application silently stops writing. Add the log directory to disk usage alerts, so a log that escapes rotation is noticed at eighty percent rather than at a hundred.
Logs that rotate also need a consumer plan. A shipper tailing a file must cope with the rename, so check that your agent follows by file identity and not only by path, or it will miss the first seconds of each new file. Compressed archives are still searchable with zgrep and zcat, and a retention of two weeks is only useful if people know where the old files are, so mention the directory in the runbook.
Where this does not apply
In containers, log to stdout and let the runtime rotate, as in Docker log rotation. Rotation does not make logs safe: compressed archives still hold sensitive data and need a retention rule to match your policy. Remote log shipping, covered in reading logs across servers, avoids losing logs when a disk dies. See the logrotate manual page and the logrotate project.


