Linux

logrotate Not Compressing on RHEL 9 / AlmaLinux 9 – /var/log Full

By September 11, 2026No Comments

On RHEL 9, AlmaLinux 9 and Rocky Linux 9 the stock /etc/logrotate.conf ships with compress commented out. A server of mine had /var/log at 4.7 GB because of it — logrotate had run perfectly every week and had simply kept four full-size copies of a runaway log on disk for a month.

Why /var/log fills up: the stock logrotate.conf has no compress

The shipped file is, in effect:

weekly
rotate 4
create
dateext

include /etc/logrotate.d

There is no compress. So every rotated file is kept at full size, and with rotate 4 you always keep four of them alongside the live one. Here is what that produced:

File Size
maillog-<date> × 4 ~990 MB each — 3.9 GB total
btmp-<date> 193 MB
messages-<date> × 4 ~77 MB each
secure-<date> 54 MB

The cause of the volume was a separate bug — a mail retry loop writing about 140 MB of maillog per day, and an SSH brute-force flood that lfd was not blocking inflating btmp. But logrotate is what multiplied it by four and kept it for a month.

Find your own version of that table before changing anything:

du -sh /var/log
ls -lhS /var/log | head -20

If the space is in /var/log/journal, logrotate will not help

Check this before you touch logrotate at all. systemd-journald manages its own storage and logrotate never sees it; on a stock RHEL 9 box with persistent storage the journal is capped at 10% of the filesystem, which is very often the single largest thing in /var/log.

journalctl --disk-usage

If that is where your space went, the fix is journald's own:

journalctl --vacuum-size=500M
# /etc/systemd/journald.conf
SystemMaxUse=1G
systemctl restart systemd-journald

Step 1. Enable compress in /etc/logrotate.conf

The shipped file already contains a commented #compress line. Uncomment it where it is — do not append compress to the bottom of the file.

The file's own comment explains why: global options do not affect preceding include directives. Options apply only to includes that come after them, so a compress added below include /etc/logrotate.d applies to nothing in that directory, and your dry run will show it silently doing nothing.

Step 2. Add maxsize to /etc/logrotate.d/rsyslog

So a fast-growing file does not have to wait for the weekly rotation:

/var/log/messages
/var/log/secure
/var/log/maillog
/var/log/cron
/var/log/spooler
{
    missingok
    sharedscripts
    maxsize 100M
    postrotate
        /usr/bin/systemctl -s HUP kill rsyslog.service >/dev/null 2>&1 || true
    endscript
}

maxsize works here because logrotate.timer runs daily — logrotate checks the size on every run and rotates early if the file is over the limit, while still honouring the weekly schedule otherwise. Confirm that on your box:

systemctl list-timers logrotate.timer

A daily schedule is what you want. On older systems this is /etc/cron.daily/logrotate instead, which is also daily. On a system where logrotate only runs weekly, maxsize buys you nothing.

Do not use size 100M here instead. size overrides the time interval entirely, so you lose the weekly rotation and get purely size-based rotation. maxsize is additive to it.

One file the rsyslog stanza does not reach: btmp is rotated by its own stanza in /etc/logrotate.d/btmp (monthly, rotate 1), so the maxsize above does not apply to it — the global compress does. Add maxsize 50M there too if a brute-force flood is inflating it.

Validate the edits with a dry run before trusting them. --debug prints exactly what logrotate would do and changes nothing:

logrotate --debug /etc/logrotate.conf

Step 3. Deal with the rotations you already have

Compression only applies to future rotations, so the existing files are yours to clear by hand. Compress them if you still want the history:

gzip /var/log/maillog-2*

Or delete them:

rm -f /var/log/{maillog,messages,secure}-2*

Never rm the live file. rsyslog keeps writing to the deleted inode and the space stays gone until the daemon is restarted. Truncate it instead:

truncate -s 0 /var/log/maillog

If df and du disagree, that is exactly what has happened somewhere — lsof +L1 lists deleted-but-still-open files.

On my box the result was 4.7 GB → 833 MB.

Do not add delaycompress here

I added it, thought about it, and removed it in the same session.

delaycompress postpones compression by one full cycle, so your 990 MB file stays uncompressed until the next rotation — precisely the thing you are trying to fix. It exists for daemons that keep writing to the old file descriptor after rotation. rsyslog is not one of them when the stanza has a postrotate that HUPs it, as the one above does: rsyslog reopens the new file immediately, so the old one is safe to compress at once.

If you have a service that genuinely keeps writing to the rotated inode, use copytruncate or a proper postrotate reload for that specific stanza — not a global delaycompress.

Verify

Force one rotation rather than waiting a day for the timer:

logrotate -f /etc/logrotate.d/rsyslog
ls -lh /var/log/*.gz
du -sh /var/log
grep maillog /var/lib/logrotate/logrotate.status

Rotated files should now end in .gz, and the status file should show a fresh rotation date.

If compress is set and rotated files still are not .gz, check for SELinux denials from logrotate — that is the other common cause of "logrotate is not compressing", and it has nothing to do with your configuration:

ausearch -m avc -ts recent | grep logrotate

Two things to watch afterwards

  • Size-based rotation shortens retention. If maxsize starts firing often, four rotations may now cover three days instead of four weeks. Raise rotate if you need the history.
  • Compression hides the real problem. 990 MB of maillog per week is a symptom. Compressed, it becomes 40 MB and stops being visible — so fix whatever is writing it. In my case it was a Postfix retry loop stuck in maildrop.

Leave a Reply