Innovate | Connect | Transform
ContactService statusUSD $

GICT knowledge base

logrotate Explained: Stop Log Files From Filling Your Disk

Published

Linux
logrotate Explained: Stop Log Files From Filling Your Disk screenshot 1

Here is a failure every server owner meets eventually. Everything runs fine for months, then one morning the site is down and the logs say No space left on device. You check, and a single log file has quietly grown to 40 GB and swallowed the disk. Nothing crashed, nothing was attacked. A log file just kept growing, because that is what log files do if nothing stops them.

The tool that stops them is logrotate, and it is already on almost every Linux server. This article explains what it does, how it works, and how to configure it safely. We set up a real log, write a rotation config, force a rotation, and watch the whole thing happen. Every command below was run before publishing.

What logrotate actually does

logrotate is a small utility that manages log files so they never grow without bound. On a schedule, it takes your current log, renames it out of the way, starts a fresh empty one, compresses the old copies, and deletes anything older than the limit you set. You end up with a bounded, tidy history like this instead of one giant file:

app.log       (current, being written)
app.log.1     (yesterday)
app.log.2.gz  (older, compressed)
app.log.3.gz  (older still, compressed)

It usually runs once a day, triggered by a cron job or a systemd timer that ships with the package. You do not run it by hand in normal operation. You just write a config once and forget about it.

How it keeps track

logrotate reads its main config from /etc/logrotate.conf and, more importantly, per-application snippets from /etc/logrotate.d/. Most packages (Nginx, Apache, MySQL) drop their own file in there on install. It records when it last rotated each file in a state file at /var/lib/logrotate/status, so even though the daily job runs every day, a “weekly” rule only actually rotates once a week.

Hands-on: rotate a log yourself

Everything here runs in a throwaway container, so your real system is never touched. First, make a log file that needs rotating:

mkdir -p /var/log/myapp
yes "$(date +%F) INFO request handled ok" | head -n 40000 > /var/log/myapp/app.log
ls -lh /var/log/myapp/app.log
1.4M /var/log/myapp/app.log

Write a rotation config

Create /etc/logrotate.d/myapp:

/var/log/myapp/app.log {
    daily
    rotate 5
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

Every line earns its place:

  • daily rotate once a day (also weekly, monthly, or size 100M to rotate by size instead).
  • rotate 5 keep 5 old copies, then delete the oldest. This is your disk-usage cap.
  • compress gzip the rotated files to save space.
  • delaycompress wait one cycle before compressing, so the most recent old log stays readable as plain text.
  • missingok do not error if the log is missing.
  • notifempty do not rotate an empty log.
  • copytruncate copy the log then truncate the original in place, instead of renaming it. More on why this matters below.

Force a rotation and watch

Normally the daily timer triggers this. To test now, force it with -f:

logrotate -f /etc/logrotate.d/myapp
ls -lh /var/log/myapp/
   0 app.log
1.4M app.log.1

The live app.log is now empty and ready for new entries, and the old 1.4M of logs moved to app.log.1. Rotate a couple more times, writing new data in between, and the chain builds up:

app.log
app.log.1
app.log.2.gz
app.log.3.gz

Notice app.log.1 is still plain text while app.log.2.gz and older are gzipped. That is delaycompress at work: the newest rotated file stays uncompressed so you can tail it immediately, and everything older gets squeezed.

The compression payoff

Compare a rotated plain-text log with its gzipped older sibling:

ls -l /var/log/myapp/app.log.1 /var/log/myapp/app.log.2.gz

Log files are highly repetitive text, so they shrink dramatically once gzipped. In practice, expect roughly a 10x to 20x reduction on real application logs, which is the difference between keeping a month of history and running out of disk.

Test without touching anything

Before trusting a config on a production box, do a dry run with -d. It prints exactly what logrotate would do and changes nothing:

logrotate -d /etc/logrotate.d/myapp
rotating pattern: /var/log/myapp/app.log  after 1 days (5 rotations)
considering log /var/log/myapp/app.log
  log does not need rotating (log has already been rotated)

This is the single most useful command for debugging a rotation rule. If your logs are not rotating, logrotate -d almost always tells you why.

The copytruncate issue (this one bites people)

Here is the subtle part that causes real incidents. By default, logrotate rotates by renaming the file: app.log becomes app.log.1, then a new app.log is created. But a long-running program that had the old file open keeps writing to it by its inode, not its name. So after rotation, your app happily keeps logging into app.log.1 while the shiny new app.log stays empty. Disk keeps filling, and you are confused.

There are two correct fixes:

  1. copytruncate (what we used): logrotate copies the log then truncates the original in place, so the file the app is holding open is the same one, now emptied. Simple, but there is a tiny window where lines written mid-copy can be lost.
  2. postrotate with a reload signal: the safer approach for software that supports it. After rotating, logrotate tells the program to reopen its log file:
/var/log/nginx/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    postrotate
        /usr/bin/systemctl reload nginx > /dev/null 2>&1 || true
    endscript
}

Nginx, Apache, and most well-behaved daemons reopen their logs cleanly on reload, which is why their packaged configs use postrotate instead of copytruncate. Use copytruncate only for apps that cannot be signaled to reopen.

A few more directives worth knowing

  • size 100M rotate when the file passes a size, regardless of the calendar. Good for logs that spike unpredictably.
  • maxage 30 delete rotated logs older than 30 days as a backstop.
  • create 0640 www-data adm set owner and permissions on the fresh log, so a new log file does not end up world-readable.
  • dateext name rotated files with a date (app.log-20260805) instead of a number, which many people find easier to read.

Wrapping up

A full disk from runaway logs is one of the most common and most avoidable ways a server falls over, and the fix is already installed. Drop a small file in /etc/logrotate.d/, set rotate and compress so history stays bounded and small, pick copytruncate or a postrotate reload depending on your app, and confirm it with logrotate -d. Do that once per service, and No space left on device stops being a 2 a.m. surprise.

Related guides

Account services are unavailable until the production backend is configured.