How to Configure Log Rotation with logrotate on RHEL 7

Log files are essential for diagnosing system problems, tracking security events, and auditing application behavior. However, without proper management, log files grow without bound and can fill your disk, causing service outages and making historical logs difficult to navigate. logrotate is the standard log rotation utility on RHEL 7. It automatically renames, compresses, and eventually discards old log files on a schedule you define. Understanding how to configure logrotate — for both system logs and your own application logs — is a foundational system administration skill that prevents countless disk-full emergencies.

Prerequisites

  • A running RHEL 7 system with root or sudo access
  • logrotate installed (it is included in the default RHEL 7 base installation)
  • Basic familiarity with text editors and the command line

Verify logrotate is installed:

rpm -q logrotate

If not present:

sudo yum install logrotate

Step 1: Understanding How logrotate Works

logrotate is typically invoked daily by a cron job installed at /etc/cron.daily/logrotate. When it runs, it reads its main configuration file and all drop-in files, then processes each log file according to the matching rules. The core behavior is:

  1. Rename the current log file with a date suffix or numeric extension (e.g., messages.1 or messages-20260517).
  2. Optionally compress the renamed file (using gzip by default).
  3. Signal the application to reopen its log file (via a postrotate script), so it begins writing to a fresh file.
  4. Remove log files older than the configured retention count.

The rotation schedule and behavior are entirely defined in configuration files — logrotate itself has no hardcoded rules about any specific log.

Step 2: The Main Configuration File — /etc/logrotate.conf

The global defaults are set in /etc/logrotate.conf. View its contents:

cat /etc/logrotate.conf

On a default RHEL 7 installation, it looks similar to this:

# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# compress rotated log files
compress

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own wtmp and btmp — rotate them here
/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}

The include /etc/logrotate.d directive tells logrotate to read all configuration files in that directory, which is where application-specific rules live.

Step 3: Understanding the /etc/logrotate.d/ Directory

Almost every package that installs a log file also installs a logrotate configuration in /etc/logrotate.d/. View the installed configurations:

ls /etc/logrotate.d/

Typical output on a RHEL 7 web server:

httpd  nginx  mysql  syslog  yum  ...etc

Look at the Apache/httpd configuration as an example:

cat /etc/logrotate.d/httpd
/var/log/httpd/*log {
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true
    endscript
}

Step 4: Core Rotation Directives Explained

The following directives are the building blocks of any logrotate configuration:

Rotation Frequency

daily        # Rotate every day
weekly       # Rotate once a week
monthly      # Rotate once a month
yearly       # Rotate once a year

Retention Count

rotate 7     # Keep 7 rotated copies before deleting the oldest

Size-Based Rotation

size 100M    # Rotate when file exceeds 100 MB (regardless of schedule)
minsize 1M   # Only rotate if file is at least 1 MB (combined with schedule)
maxsize 500M # Force rotation if file exceeds this size even before the schedule

Compression

compress         # Compress rotated files with gzip
nocompress       # Do not compress
delaycompress    # Delay compression until the next rotation cycle (useful for services
                 # that may still be writing to the just-rotated file)
compresscmd /usr/bin/bzip2   # Use bzip2 instead of gzip
compressext .bz2             # Set the compressed file extension

File Handling

missingok      # Do not report an error if the log file is missing
notifempty     # Do not rotate if the log file is empty
create         # Create a new empty log file after rotation
create 0640 root adm   # Create with specific permissions, owner, group
nocreate       # Do not create a new log file after rotation
copytruncate   # Copy log then truncate original (for apps that can't reopen logs)

Date-Based Naming

dateext           # Append a date instead of a number (e.g., logfile-20260517.gz)
dateformat -%Y%m%d   # Customize the date format

Script Hooks

postrotate
    /bin/systemctl reload myservice > /dev/null 2>&1 || true
endscript

prerotate
    echo "About to rotate" >> /var/log/rotation.log
endscript

sharedscripts   # Run postrotate/prerotate only once even if multiple files matched

Step 5: Creating a Custom logrotate Configuration

Suppose you have a custom application writing logs to /var/log/myapp/app.log. Create a dedicated logrotate configuration for it:

sudo vi /etc/logrotate.d/myapp

Paste the following:

/var/log/myapp/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 myappuser myappgroup
    dateext
    dateformat -%Y%m%d
    sharedscripts
    postrotate
        /bin/systemctl reload myapp.service > /dev/null 2>&1 || true
    endscript
}

Breaking down this configuration:

  • Rotates all .log files in /var/log/myapp/ daily.
  • Keeps 14 days of history.
  • Compresses old files, but delays compressing the most recent rotation (in case the app is still writing to it briefly after rotation).
  • Skips rotation if the file is missing or empty.
  • Creates a new empty log file owned by the application’s user and group.
  • Appends date-formatted suffixes to rotated files.
  • Sends a reload signal to the service so it reopens its log file descriptor.

Step 6: Testing logrotate Configuration

Before relying on a new configuration, always test it to catch syntax errors and verify behavior.

Dry Run with -d (Debug Mode)

The -d flag runs logrotate in debug mode. It reads all configuration, shows what it would do, but makes no changes:

sudo logrotate -d /etc/logrotate.d/myapp

Review the output carefully. It will show which files match, whether rotation conditions are met, and what actions would be taken.

Force Rotation with -f

To force an immediate rotation regardless of whether the rotation condition (daily, size, etc.) is met:

sudo logrotate -f /etc/logrotate.d/myapp

To force a full rotation of all configurations:

sudo logrotate -f /etc/logrotate.conf

Verbose Mode

Combine -v with -f for detailed output:

sudo logrotate -vf /etc/logrotate.d/myapp

Checking the State File

logrotate tracks when it last rotated each file in a state file at /var/lib/logrotate/logrotate.status (or /var/lib/logrotate.status on some RHEL 7 versions):

cat /var/lib/logrotate/logrotate.status | grep myapp

Example output:

"/var/log/myapp/app.log" 2026-5-17-6:0:0

You can delete entries from this file to force logrotate to treat a file as never rotated, or modify timestamps to test time-based rotation logic.

Step 7: Managing the systemd Journal Size

On RHEL 7, systemd’s journal (journald) maintains its own separate log store and is not managed by logrotate. By default, the journal is stored in /run/log/journal/ (volatile, lost on reboot) unless persistent storage is configured. Control its size through /etc/systemd/journald.conf:

sudo vi /etc/systemd/journald.conf

Relevant size-limiting directives:

[Journal]
# Maximum total disk space the journal may use
SystemMaxUse=500M

# Leave at least this much free on the filesystem
SystemKeepFree=1G

# Maximum size of an individual journal file before it is rotated internally
SystemMaxFileSize=50M

# Maximum time to keep journal entries
MaxRetentionSec=1month

# For volatile (in-memory) journal:
RuntimeMaxUse=100M

After editing, restart journald to apply the changes:

sudo systemctl restart systemd-journald

To manually vacuum the journal down to a target size:

# Remove journal files until total size is under 200MB
sudo journalctl --vacuum-size=200M

# Remove journal files older than 2 weeks
sudo journalctl --vacuum-time=2weeks

# Show current journal disk usage
sudo journalctl --disk-usage

Step 8: Troubleshooting Common logrotate Issues

A few common problems and their solutions:

Log file not being rotated

Check the state file to see the last rotation time. If it was rotated recently, the schedule has not elapsed. Use -f to force it for testing.

Application still writing to old log file after rotation

The postrotate script must signal the application to close and reopen its log file descriptor. If the application does not support signals for this, use copytruncate instead:

/var/log/myapp/*.log {
    daily
    rotate 14
    compress
    copytruncate
    missingok
    notifempty
}

copytruncate copies the log to a rotated file and then truncates the original, so the running application never loses its file descriptor. Note there is a brief window where log entries may be lost between the copy and the truncate.

Permission denied errors in postrotate

Ensure the command in postrotate uses full paths and that logrotate (running as root via cron) has permission to execute it.

Conclusion

logrotate is a simple but powerful tool that prevents disk exhaustion from runaway log files on RHEL 7 systems. You have learned how the /etc/logrotate.conf global configuration works, how to place application-specific rules in /etc/logrotate.d/, the meaning of all major rotation directives, how to create a custom configuration for your own application’s logs, and how to test configurations safely before they go live. Combine logrotate management for traditional log files with proper journald size limits for systemd-managed services, and you will have comprehensive log lifecycle control across your entire RHEL 7 system. Schedule a periodic review of your retention settings as your system grows to ensure disk usage remains within acceptable bounds.