logrotate in practice: copytruncate and -f, tested on Rocky 9
When to use it
Section titled “When to use it”An application writing its own log file will fill the partition within days. logrotate ships with EL and rotates by time or size, compresses, and keeps N copies. This page walks the full flow on a self-managed app log.
Install and read the defaults
Section titled “Install and read the defaults”sudo dnf install -y logrotatehead -20 /etc/logrotate.confls /etc/logrotate.d/ | head -5btmpdnfwtmpEvery file under /etc/logrotate.d/ is a snippet; the system’s own btmp and wtmp live there. Do not stuff app configuration into logrotate.conf — a file in /etc/logrotate.d/ is cleaner.
Write a snippet for your app
Section titled “Write a snippet for your app”cat | sudo tee /etc/logrotate.d/myapp <<'EOF'/var/log/myapp/*.log { daily rotate 3 compress missingok notifempty copytruncate}EOFWhat the six directives do:
| Directive | Effect |
|---|---|
daily | Rotate once a day (or use size 50M, weekly) |
rotate 3 | Keep 3 older files; delete from the 4th on |
compress | gzip the rotated file |
missingok | No error when the log is absent |
notifempty | Do not rotate an empty file |
copytruncate | Copy then truncate the original — the app does not need to reopen its file handle |
Dry-run first, then force one rotation
Section titled “Dry-run first, then force one rotation”sudo logrotate -d /etc/logrotate.d/myapprotating pattern: /var/log/myapp/*.log after 1 days (3 rotations)empty log files are not rotated, old logs are removedconsidering log /var/log/myapp/app.log... log does not need rotating (log has already been rotated)-d is a dry-run: it prints but changes nothing. When the configuration looks right, force one run:
sudo logrotate -f /etc/logrotate.d/myappls -l /var/log/myapp/-rw-r--r-- 1 root root 0 Oct 18 15:44 app.log-rw-r--r-- 1 root root 4023 Oct 18 15:44 app.log.1.gzapp.log is truncated to 0 bytes and the content moved into app.log.1.gz — that is copytruncate in action.
Tested on EL10: the same stanza on Alma/Rocky 10.2
Section titled “Tested on EL10: the same stanza on Alma/Rocky 10.2”In PVE VMs running AlmaLinux 10.2 and Rocky Linux 10.2, with the same stanza:
/var/log/lab/app.log { daily rotate 3 copytruncate notifempty missingok su root root}logrotate -d dry run (the state file says it already rotated today):
log does not need rotating (log has already been rotated)After logrotate -f:
-rw-r--r--. 1 root root 0 ... app.log-rw-r--r--. 1 root root 21 ... app.log.1Write one more line, force again:
-rw-r--r--. 1 root root 0 ... app.log-rw-r--r--. 1 root root 5 ... app.log.1-rw-r--r--. 1 root root 21 ... app.log.2copytruncate behaves exactly as advertised: the active file becomes 0 bytes, the old content moves to .1, and the next rotation shifts .1 to .2. Writers do not reopen the file; the cost is a tiny window between copy and truncate where a few lines can be lost.
Common traps
Section titled “Common traps”copytruncateloses lines: anything written between the copy and the truncate is lost; applications that can reopen their handle should usecreateplus apostrotatesignal instead;sizewithoutdaily:sizetriggers regardless of time; do not mix it withdailyand expect once-a-day;- Ownership: if
/var/log/myappis not owned by root, the file created aftercopytruncatemay have the wrong owner; addsu myapp myappwhen needed.
Practice: keep 3 rotations and verify
Section titled “Practice: keep 3 rotations and verify”Prerequisite: Rocky 9 with logrotate installed.
sudo mkdir -p /var/log/lab && sudo sh -c 'head -c 200000 /dev/urandom > /var/log/lab/a.log'sudo tee /etc/logrotate.d/lab >/dev/null <<'EOF'/var/log/lab/*.log { daily rotate 3 compress copytruncate }EOFsudo logrotate -f /etc/logrotate.d/lab # run 1sudo logrotate -f /etc/logrotate.d/lab # run 2ls /var/log/lab/Checks:
a.log.1.gzanda.log.2.gzexista.logis 0 bytes- After five forced runs, no more than 3
*.gzfiles remain (rotate 3works)
Next steps
Section titled “Next steps”- How scheduling works:
logrotateis called from/etc/cron.daily/logrotate - Offline installs: Offline package installs
- Post-install checks: First-hour checks