logrotate — Logs That Don't Fill the Disk
Logs only grow. An app that logs every request writes gigabytes in a month — until the disk is full and everything stops. logrotate keeps them in check: every day (or week) it renames the log, starts a fresh one, compresses the old ones and deletes the oldest.
ls -lh /var/log/myapp
-rw-r----- 1 root adm 179M Nov 1 15:38 app.log
-rw-r----- 1 root adm 48K Nov 1 13:39 error.log
Nobody set up rotation for this app's logs.
How it's set up
/etc/logrotate.conf has the defaults; every package drops its own file in /etc/logrotate.d:
ls /etc/logrotate.d
cat /etc/logrotate.d/dpkg
/var/log/dpkg.log {
monthly
rotate 12
compress
delaycompress
missingok
notifempty
create 644 root root
}
| Line | Means |
|---|---|
daily / weekly / monthly | how often |
rotate 12 | keep 12 old copies, delete the older ones |
compress | gzip the old copies |
delaycompress | …but not the newest old one (a program may still write to it) |
missingok | no error when the log isn't there |
notifempty | leave an empty log alone |
create 644 root root | a new, empty log with this mode and owner |
size 100M | rotate once it's this big, whatever the date |
copytruncate | copy, then empty the log in place — for apps that keep it open |
One for myapp
sudo tee /etc/logrotate.d/myapp > /dev/null << 'EOF'
/var/log/myapp/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 root adm
}
EOF
Test it
-d (debug) tells what it would do — and does nothing:
sudo logrotate -d /etc/logrotate.d/myapp
considering log /var/log/myapp/app.log
Creating new state
Now: 2026-11-01 15:39
Last rotated at 2026-11-01 15:00
log does not need rotating (log has already been rotated)
A log logrotate meets for the first time counts as rotated this hour: the first real rotation is tomorrow. -f forces one now:
sudo logrotate -f /etc/logrotate.d/myapp
ls -lh /var/log/myapp
-rw-r----- 1 root adm 0 Nov 1 15:39 app.log
-rw-r----- 1 root adm 179M Nov 1 15:38 app.log.1
Tomorrow app.log.1 becomes app.log.2.gz, and so on up to .7.gz; when each log was last rotated is in /var/lib/logrotate/status. And who runs it every day?
systemctl list-timers logrotate.timer
💡 After a rotation an app may go on writing to the old, renamed file — it still has it open. A
postrotatescript (systemctl reload myapp) orcopytruncatetakes care of that.