--- title: "How to Configure Logrotate on Ubuntu 24.04" description: "Configure logrotate on Ubuntu 24.04 to rotate, compress and expire application logs, signal services after rotation, and test every rule before it runs." category: "Monitoring Logging" language: en source: https://cubepath.com/docs/monitoring-logging/logrotate-configuration updated: 2026-09-25 --- # How to Configure Logrotate on Ubuntu 24.04 Logrotate renames, compresses and deletes old log files on a schedule so that `/var/log` never fills the disk. Ubuntu ships it preinstalled and already rotates the logs of system packages such as Nginx, rsyslog and apt. In this tutorial you will learn how the default setup works on Ubuntu 24.04, write a rotation policy for your own application, make the application reopen its log file after rotation, and test the rule before relying on it. ## Prerequisites To follow this guide you need: - A server running Ubuntu 24.04 LTS, for example a CubePath VPS. The same files and commands apply to Debian 12. - A non-root user with `sudo` privileges. - An application that writes plain log files. The examples use a service called `myapp` that writes to `/var/log/myapp/`; replace the names with your own. ## Step 1 - Checking how logrotate runs On Ubuntu 24.04, logrotate is started once a day by a systemd timer, not by cron. Confirm that the package is installed and the timer is active: ```bash logrotate --version systemctl list-timers logrotate.timer ``` ```output logrotate 3.21.0 ... NEXT LEFT LAST PASSED UNIT ACTIVATES Thu 2026-09-26 00:00:00 UTC 9h left Wed 2026-09-25 00:00:04 UTC 14h ago logrotate.timer logrotate.service ``` Each run executes `logrotate.service`, and its output goes to the journal. Check the last run for errors: ```bash journalctl -u logrotate.service -n 20 --no-pager ``` A file `/etc/cron.daily/logrotate` may also exist, but it exits immediately on systemd systems, so the timer is the only scheduler that matters. ## Step 2 - Understanding the configuration files Logrotate reads three locations: | Path | Purpose | |------|---------| | `/etc/logrotate.conf` | Global defaults and the `include` of the directory below | | `/etc/logrotate.d/` | One file per package or application with its own rules | | `/var/lib/logrotate/status` | State file with the date each log was last rotated | Open the global file to see the defaults: ```bash cat /etc/logrotate.conf ``` ```output weekly su root adm rotate 4 create #dateext #compress include /etc/logrotate.d ``` These settings apply to every rule that does not override them: rotate weekly, keep four old copies and create an empty log after rotating. Package rules in `/etc/logrotate.d/` usually override them. For example, the Nginx rule installed by the `nginx` package looks like this: ```bash cat /etc/logrotate.d/nginx ``` ```output /var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts prerotate if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ run-parts /etc/logrotate.d/httpd-prerotate; \ fi \ endscript postrotate invoke-rc.d nginx rotate >/dev/null 2>&1 endscript } ``` Leave package files as they are unless you need different retention: your changes can conflict with future package upgrades, which ask whether to keep your version. ## Step 3 - Learning the directives you will use A rule is a path (wildcards allowed) followed by directives in braces. These are the ones that matter in almost every configuration: | Directive | Effect | |-----------|--------| | `daily`, `weekly`, `monthly` | Rotation frequency | | `size 100M` | Rotate only when the file exceeds the size, ignoring the frequency | | `maxsize 100M` | Rotate at the scheduled time or earlier if the size is exceeded | | `rotate 14` | Number of old files to keep; older ones are deleted | | `maxage 30` | Delete rotated files older than 30 days | | `compress` / `delaycompress` | Gzip old files; `delaycompress` leaves the most recent one uncompressed | | `missingok` | Do not fail if the log does not exist | | `notifempty` | Skip rotation when the file is empty | | `create 0640 user group` | Create a new empty log with this mode and owner after rotating | | `copytruncate` | Copy the log and truncate the original instead of renaming it | | `dateext` | Use a date suffix (`app.log-20260925`) instead of `.1`, `.2` | | `sharedscripts` | Run `postrotate` once for all matched files, not once per file | | `postrotate` ... `endscript` | Shell commands run after rotating, usually to reopen logs | | `su user group` | Rotate as this user and group instead of root | Size checks only happen when logrotate runs, so with the default daily timer `size 100M` means "at most once a day, if the file is larger than 100 MB". ## Step 4 - Creating a rotation rule for your application Suppose `myapp` runs as the `myapp` user and writes `/var/log/myapp/app.log` and `/var/log/myapp/error.log`. Create a dedicated file for it: ```bash sudo nano /etc/logrotate.d/myapp ``` Add the following rule: ```text /var/log/myapp/*.log { daily rotate 14 maxsize 200M compress delaycompress missingok notifempty dateext su myapp myapp create 0640 myapp myapp sharedscripts postrotate pkill -HUP -x myapp || true endscript } ``` This keeps two weeks of daily logs, rotates earlier if a file grows past 200 MB, and compresses everything except the most recent rotated file. The `su myapp myapp` line is needed because `/var/log/myapp` is owned by `myapp`: logrotate refuses to work in a directory that is writable by a non-root user unless you tell it which user to act as. The `postrotate` block sends `SIGHUP` to processes named exactly `myapp` so they close the renamed file and open a new `app.log`. Replace it with the reload mechanism your application actually documents. Because of `su`, the script runs with the `myapp` identity, which is allowed to signal its own processes; a command that needs root (such as `systemctl reload`) would fail here. The `|| true` keeps logrotate from reporting an error when the application is stopped. Save the file. Logrotate needs rule files to be owned by root and not writable by others, which is the default when you create them with `sudo`. ### When the application cannot reopen its log Some programs keep the file open forever and have no reload signal, so after a rename they keep writing to the rotated file. For those, replace `create` and the `postrotate` block with `copytruncate`: ```text /var/log/legacyapp/output.log { daily rotate 7 compress delaycompress missingok notifempty copytruncate } ``` Logrotate copies the file and then truncates the original in place. The trade-off is that lines written between the copy and the truncate are lost, so prefer `create` plus a reload whenever the application supports it. ## Step 5 - Testing the rule Run logrotate in debug mode against your file. Debug mode shows what would happen without touching any log: ```bash sudo logrotate -d /etc/logrotate.d/myapp ``` ```output reading config file /etc/logrotate.d/myapp ... rotating pattern: /var/log/myapp/*.log after 1 days empty log files are not rotated, (14 rotations), old logs are removed considering log /var/log/myapp/app.log ... log does not need rotating (log has been already rotated) ``` Syntax errors such as an unknown directive or a missing brace appear at the top of this output. When the rule parses cleanly, force a real rotation to check permissions and the reload command: ```bash sudo logrotate -vf /etc/logrotate.d/myapp ``` Then list the directory: ```bash ls -l /var/log/myapp/ ``` ```output -rw-r----- 1 myapp myapp 0 Sep 25 14:05 app.log -rw-r----- 1 myapp myapp 8211 Sep 25 14:05 app.log-20260925 -rw-r----- 1 myapp myapp 0 Sep 25 14:05 error.log -rw-r----- 1 myapp myapp 512 Sep 25 14:05 error.log-20260925 ``` The rotated files are not compressed yet because of `delaycompress`; they will be gzipped on the next run. Generate some activity in the application and confirm that new lines go to `app.log`, not to the dated file. If they still go to the old file, the reload in `postrotate` is not working. Finally, check that the state file recorded the rotation: ```bash sudo grep myapp /var/lib/logrotate/status ``` ```output "/var/log/myapp/app.log" 2026-9-25-14:5:0 "/var/log/myapp/error.log" 2026-9-25-14:5:0 ``` ## Step 6 - Rotating more often than once a day (optional) The `hourly` directive only works if logrotate itself runs every hour. To change the schedule, create a drop-in for the timer instead of editing the packaged unit: ```bash sudo systemctl edit logrotate.timer ``` Add these lines in the editor. The empty `OnCalendar=` clears the packaged daily schedule before setting the new one: ```ini [Timer] OnCalendar= OnCalendar=hourly ``` Save and confirm the next run time: ```bash systemctl list-timers logrotate.timer ``` The next run should now be at the top of the next hour. Rules with `daily` or `weekly` are not affected: logrotate uses the state file to decide whether each log is due. ## Troubleshooting **"skipping ... because parent directory has insecure permissions"**: the log directory is writable by a user or group other than root. Add a `su user group` line with the owner of the directory, as in Step 4. Do not loosen the directory permissions to fix it. **The log is not rotating**: run `sudo logrotate -d /etc/logrotate.d/yourfile` and read the reason for each file. Common causes are `notifempty` on an empty file, a `size` threshold that has not been reached, or the state file showing it was already rotated in the current period. **The application keeps writing to the rotated file**: the `postrotate` command did not make the process reopen its log. Verify the signal or reload command by running it by hand, or switch to `copytruncate`. **A rule in `/etc/logrotate.d/` is ignored**: logrotate skips files with names that match its `tabooext` list, such as `.dpkg-old` or `.dpkg-dist`, and files that are group or world writable. Keep the file name plain and its mode `0644`. **Logs from the systemd journal keep growing**: the journal is not managed by logrotate. Limit it with `SystemMaxUse=` in `/etc/systemd/journald.conf` instead. ## Conclusion You now know how Ubuntu 24.04 schedules logrotate, how to write a rule with retention, compression and a safe reload, and how to test it with `-d` and `-f` before it runs unattended. As next steps, review the retention of noisy package logs in `/etc/logrotate.d/`, cap the systemd journal size in `journald.conf`, and ship important logs to a central system so that local rotation is not your only copy.