How to Configure Logrotate for Application Logs on RHEL 7

Log files are essential for diagnosing problems and auditing system activity, but left unmanaged they will silently consume all available disk space and eventually bring a server to a halt. Logrotate is the standard tool on RHEL 7 for automating log file rotation, compression, and pruning. It runs daily as a cron job, reads configuration files from /etc/logrotate.d/, and applies rules you define — rotating files by age or size, compressing old logs, executing post-rotation commands to signal applications, and generating date-stamped archive filenames. This guide covers every major configuration option, size-based and date-based rotation strategies, manual execution, debugging techniques, and the relationship between logrotate and rsyslog.

Prerequisites

  • RHEL 7 server with root or sudo access
  • Logrotate installed — it is included in the base installation; verify with rpm -q logrotate
  • An application writing log files to a known path (examples here use nginx and a custom application)
  • Basic familiarity with the application’s signal handling (most daemons support SIGUSR1 or HUP to reopen log files)

Step 1: Understand How Logrotate Works on RHEL 7

Logrotate is invoked by a daily cron job defined in /etc/cron.daily/logrotate. This script runs once per day, typically in the early morning, and processes every configuration file it finds in /etc/logrotate.d/ as well as the global defaults in /etc/logrotate.conf. The global file sets system-wide defaults; files in /etc/logrotate.d/ override or extend those defaults on a per-application basis.

# View the main logrotate configuration
cat /etc/logrotate.conf

# List all per-application configuration files
ls -la /etc/logrotate.d/

Logrotate maintains state in /var/lib/logrotate/logrotate.status, which records the last time each log file was rotated. This prevents double-rotation if the tool is accidentally run twice in the same day.

Step 2: Create a Logrotate Configuration for Your Application

Drop a file named after your application into /etc/logrotate.d/. The file name is arbitrary — use something descriptive. Here is a comprehensive configuration for a custom application that writes to /var/log/myapp/:

cat > /etc/logrotate.d/myapp <<'EOF'
/var/log/myapp/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0644 myapp myapp
    dateext
    dateformat -%Y%m%d
    sharedscripts
    postrotate
        # Signal the application to reopen its log file handles
        [ -f /var/run/myapp.pid ] && kill -USR1 $(cat /var/run/myapp.pid) || true
    endscript
}
EOF

What Each Directive Does

  • daily — Rotate once per day. Alternatives are weekly, monthly, and yearly.
  • rotate 14 — Keep 14 rotated copies before deleting the oldest. Combined with daily, this retains two weeks of history.
  • compress — Compress rotated log files with gzip. This typically reduces file size by 70–90% for text logs.
  • delaycompress — Postpone compression of the most recently rotated file by one rotation cycle. This is essential for applications that keep the old file descriptor open briefly after rotation — without it, the application might still be writing to the file being compressed.
  • missingok — Do not report an error if the log file does not exist (useful during application downtime or initial setup).
  • notifempty — Skip rotation if the log file is empty. Prevents cluttering the archive with zero-byte compressed files.
  • create 0644 myapp myapp — After rotation, immediately create a new empty log file with the specified permissions and ownership so the application can continue writing without interruption.
  • dateext — Append the rotation date to the archived filename instead of a plain numeric suffix (e.g., app.log-20260517 instead of app.log.1).
  • dateformat -%Y%m%d — Format string for the date extension. The leading dash separates the base name from the date.
  • sharedscripts — When the pattern matches multiple log files, run the postrotate script only once rather than once per file.
  • postrotate / endscript — Shell commands executed after rotation. Used to signal the application to reopen its log files.

Step 3: Configure Nginx Log Rotation

Nginx uses SIGUSR1 to reopen its log files. RHEL 7’s nginx package installs its own logrotate configuration at /etc/logrotate.d/nginx. Review and customise it:

cat > /etc/logrotate.d/nginx <<'EOF'
/var/log/nginx/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0640 nginx adm
    dateext
    dateformat -%Y%m%d
    sharedscripts
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 $(cat /var/run/nginx.pid)
        fi
    endscript
}
EOF

For Apache (httpd), which uses SIGUSR1 via the apachectl graceful restart mechanism, the postrotate script should instead use:

    postrotate
        /bin/systemctl reload httpd.service > /dev/null 2>&1 || true
    endscript

Step 4: Use Size-Based Rotation

Time-based rotation is predictable but unsuitable for high-volume log sources that can fill a disk within hours. Use the size directive to trigger rotation when a file reaches a threshold regardless of time:

# /etc/logrotate.d/myapp-highvolume
/var/log/myapp/access.log {
    size 100M
    rotate 10
    compress
    delaycompress
    missingok
    notifempty
    create 0644 myapp myapp
    dateext
    sharedscripts
    postrotate
        [ -f /var/run/myapp.pid ] && kill -USR1 $(cat /var/run/myapp.pid) || true
    endscript
}

Size values can be specified in bytes (100k), kilobytes (100k), megabytes (100M), or gigabytes (1G). Note that size-based rotation only triggers when logrotate runs — by default once per day. For true size-based rotation at sub-daily intervals, combine size with a more frequent cron job:

# Run logrotate every hour
echo "0 * * * * root /usr/sbin/logrotate /etc/logrotate.conf" 
    > /etc/cron.d/logrotate-hourly

Step 5: Use dateext for Date-Stamped Archive Filenames

Without dateext, logrotate names archives app.log.1, app.log.2, and so on — renaming every file on each rotation cycle, which makes scripted log searches difficult. With dateext, each archive gets a unique, human-readable name:

# Result with dateext + dateformat -%Y%m%d:
ls -lh /var/log/myapp/
# app.log               ← current log
# app.log-20260517.gz   ← yesterday's log, compressed
# app.log-20260516.gz
# app.log-20260515.gz

If you rotate more than once per day, add the time component to avoid filename collisions:

dateformat -%Y%m%d-%H%M%S

Step 6: Run Logrotate Manually

To trigger an immediate rotation without waiting for the daily cron job, use the -f (force) flag. This is useful after deploying an application or when disk space is running low:

# Force rotation of all configurations
logrotate -f /etc/logrotate.conf

# Force rotation of a specific configuration only
logrotate -f /etc/logrotate.d/myapp

The -f flag overrides the notifempty and recency checks, so rotation happens even if logrotate already ran today.

Step 7: Debug Logrotate Configuration

The -d (debug) flag runs logrotate in dry-run mode — it prints every action it would take without actually rotating, compressing, or executing postrotate scripts. Use it to validate a new configuration before it runs in production:

# Debug mode — no files are modified
logrotate -d /etc/logrotate.d/myapp

Sample output shows which files match, whether rotation is needed, and what the postrotate script would execute:

reading config file /etc/logrotate.d/myapp
Allocating hash table for state file, size 64 entries

Handling 1 logs

rotating pattern: /var/log/myapp/*.log  after 1 days (14 rotations)
empty log files are not rotated, old logs are removed
switching euid to 0 and egid to 0
considering log /var/log/myapp/app.log
  log needs rotating

For more verbose output, combine -d with -v:

logrotate -dv /etc/logrotate.d/myapp

If logrotate reports an error about a configuration file, check file syntax carefully — a common mistake is omitting the closing brace or misquoting a path with spaces:

# Validate configuration syntax
logrotate --debug /etc/logrotate.d/myapp 2>&1 | head -20

Step 8: Logrotate and rsyslog Interaction

The system logger rsyslog writes to /var/log/messages, /var/log/secure, /var/log/maillog, and other files. These are managed by the /etc/logrotate.d/syslog configuration that ships with RHEL 7. After rotating, logrotate must signal rsyslog to reopen its file descriptors:

# The default /etc/logrotate.d/syslog postrotate script:
postrotate
    /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript

On RHEL 7 with rsyslog, you can also use systemctl to send the signal reliably:

postrotate
    /bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true
endscript

View the current syslog logrotate configuration to understand how RHEL 7 handles its own system logs:

cat /etc/logrotate.d/syslog

Conclusion

Logrotate is a simple but powerful tool that, once correctly configured, runs silently in the background and ensures your log directories never fill the disk. By creating a dedicated configuration file in /etc/logrotate.d/ for each application, combining compress with delaycompress, using dateext for human-readable archive names, and writing accurate postrotate scripts to signal your applications, you establish a maintainable and reliable log management strategy. The -d debug flag and -f force flag give you the confidence to test changes and trigger immediate rotations when needed, while the interaction with rsyslog ensures system logs are handled consistently alongside your application logs.