Logrotate Configuration: Complete Guide
Introduction
Log files are essential for monitoring system health, debugging applications, and maintaining security, but without proper management, they can quickly consume valuable disk space and make log analysis difficult. Logrotate is a powerful utility that automates log file rotation, compression, and removal, ensuring your logs remain manageable while preserving historical data when needed.
Logrotate handles the entire lifecycle of log files by automatically rotating them based on size or time intervals, compressing old logs to save space, and removing ancient logs according to retention policies. This automation prevents disk space exhaustion, maintains system performance, and ensures compliance with data retention requirements.
In this comprehensive guide, we'll explore logrotate configuration from basic concepts to advanced implementations. You'll learn how to configure rotation policies for system logs, application logs, and custom services, implement compression strategies, manage retention periods, and troubleshoot common issues. Whether you're managing a single server or a fleet of systems, mastering logrotate is essential for maintaining a healthy logging infrastructure.
Prerequisites
Before configuring logrotate, ensure you have:
- A Linux server (Ubuntu 20.04/22.04, Debian 10/11, CentOS 7/8, Rocky Linux 8/9, or similar)
- Root or sudo access to modify system configurations
- Basic understanding of Linux file system and permissions
- Familiarity with log file locations (typically
/var/log/) - Text editor (nano, vim, or vi)
System Requirements:
- Logrotate package installed (usually pre-installed on most distributions)
- Sufficient disk space for temporary log files during rotation
- Cron daemon running for scheduled rotation
Installing and Verifying Logrotate
Most Linux distributions include logrotate by default, but let's verify and install if needed.
Installation
On Ubuntu/Debian:
# Check if logrotate is installed
dpkg -l | grep logrotate
# Install if not present
sudo apt update
sudo apt install logrotate -y
# Verify installation
logrotate --version
On CentOS/Rocky Linux/AlmaLinux:
# Check if logrotate is installed
rpm -qa | grep logrotate
# Install if not present
sudo yum install logrotate -y
# Verify installation
logrotate --version
Verify Logrotate Service
# Check logrotate systemd timer (if using systemd)
systemctl list-timers | grep logrotate
# View logrotate cron job
cat /etc/cron.daily/logrotate
# Check logrotate status file
cat /var/lib/logrotate/status
# or on older systems
cat /var/lib/logrotate.status
Understanding Logrotate Architecture
Main Configuration File
The primary configuration file is /etc/logrotate.conf:
# View main configuration
sudo cat /etc/logrotate.conf
Typical logrotate.conf structure:
# Global options
weekly
rotate 4
create
dateext
compress
# Package-specific configuration files
include /etc/logrotate.d
# System-specific logs
/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M
rotate 1
}
/var/log/btmp {
missingok
monthly
create 0600 root utmp
rotate 1
}
Configuration Directory
Application-specific configurations are stored in /etc/logrotate.d/:
# List all logrotate configurations
ls -l /etc/logrotate.d/
# Example configurations
/etc/logrotate.d/apache2
/etc/logrotate.d/nginx
/etc/logrotate.d/mysql-server
/etc/logrotate.d/rsyslog
Status File
Logrotate tracks rotation history in a status file:
# View current rotation status
sudo cat /var/lib/logrotate/status
# Example output:
# "/var/log/syslog" 2024-1-11-3:0:0
# "/var/log/auth.log" 2024-1-11-3:0:0
# "/var/log/nginx/access.log" 2024-1-10-3:0:0
Logrotate Configuration Syntax
Basic Configuration Structure
A logrotate configuration file consists of log file patterns and directives:
# Basic structure
/path/to/logfile {
# Rotation directives
directive1
directive2 value
# Scripts
prerotate
# commands before rotation
endscript
postrotate
# commands after rotation
endscript
}
Common Directives
Rotation Frequency:
daily # Rotate logs daily
weekly # Rotate logs weekly (on Sunday by default)
monthly # Rotate logs monthly (on first day of month)
yearly # Rotate logs yearly (on January 1st)
Rotation Conditions:
size 100M # Rotate when file reaches 100MB
minsize 10M # Rotate only if file is at least 10MB
maxsize 500M # Force rotation if file exceeds 500MB
rotate 7 # Keep 7 rotated logs
maxage 30 # Remove logs older than 30 days
File Handling:
compress # Compress rotated logs with gzip
nocompress # Don't compress logs
delaycompress # Compress on next rotation (keep one uncompressed)
compresscmd gzip # Specify compression command
compressext .gz # Specify compression extension
compressoptions -9 # Maximum compression
create 0640 user group # Create new log with permissions
nocreate # Don't create new log file
copy # Copy log instead of moving
copytruncate # Copy then truncate original log
Missing Files:
missingok # Don't error if log file is missing
notifempty # Don't rotate if log is empty
ifempty # Rotate even if log is empty
Old Log Handling:
dateext # Add date extension (e.g., .20240111)
dateformat -%Y%m%d # Custom date format
extension .log # Extension to preserve
olddir /path/to/old # Move old logs to directory
noolddir # Keep old logs in same directory
Mailing:
mail [email protected] # Email log before deletion
nomail # Don't email logs
mailfirst # Mail newest log
maillast # Mail oldest log (default)
Shared Logs:
sharedscripts # Run scripts once for all matching logs
nosharedscripts # Run scripts for each log separately
Basic Logrotate Configurations
Simple Daily Rotation
# Create configuration: /etc/logrotate.d/myapp
sudo nano /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 myapp myapp
}
Explanation:
- Rotate all
.logfiles in/var/log/myapp/daily - Keep 7 days of logs
- Compress old logs (but delay compression by one rotation)
- Don't error if logs are missing
- Don't rotate empty logs
- Create new logs with specific permissions and ownership
Size-Based Rotation
# Configuration for large application logs
/var/log/application/app.log {
size 100M
rotate 5
compress
missingok
notifempty
create 0644 appuser appgroup
dateext
}
Explanation:
- Rotate when log reaches 100MB
- Keep 5 rotated copies
- Add date extension to rotated files
- Compress rotated logs immediately
Weekly Rotation with Old Directory
/var/log/backup/*.log {
weekly
rotate 4
compress
delaycompress
missingok
notifempty
create 0640 root root
olddir /var/log/backup/old
dateext
dateformat -%Y%m%d
}
Explanation:
- Rotate weekly (every Sunday)
- Keep 4 weeks of logs
- Move old logs to separate directory
- Add custom date format to filenames
Advanced Logrotate Configurations
Web Server Logs (Nginx)
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
rotate 14
compress
delaycompress
missingok
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
[ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
Key features:
- Rotates daily, keeps 2 weeks
- Uses
sharedscriptsto run postrotate once - Signals nginx to reopen log files after rotation
Apache Web Server
# /etc/logrotate.d/apache2
/var/log/apache2/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 root adm
sharedscripts
postrotate
/usr/sbin/apache2ctl graceful > /dev/null 2>&1 || true
endscript
}
MySQL/MariaDB Logs
# /etc/logrotate.d/mysql-server
/var/log/mysql/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 mysql adm
sharedscripts
postrotate
if test -x /usr/bin/mysqladmin && \
/usr/bin/mysqladmin ping &>/dev/null
then
/usr/bin/mysqladmin --local flush-error-log \
flush-engine-log flush-general-log flush-slow-log
fi
endscript
}
Application Logs with Custom Scripts
# /etc/logrotate.d/custom-app
/var/log/custom-app/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 0644 appuser appgroup
dateext
dateformat -%Y%m%d-%s
maxsize 500M
prerotate
# Notify monitoring system
echo "Rotating logs for custom-app" | \
logger -t logrotate
# Backup critical logs before rotation
if [ -f /var/log/custom-app/critical.log ]; then
cp /var/log/custom-app/critical.log \
/backup/logs/critical-$(date +%Y%m%d).log
fi
endscript
postrotate
# Restart application to use new log file
systemctl reload custom-app.service
# Update log index
/usr/local/bin/update-log-index.sh
endscript
firstaction
# Run before any logs are rotated
mkdir -p /backup/logs
endfirstaction
lastaction
# Run after all logs are rotated
/usr/local/bin/cleanup-old-backups.sh
endlastaction
}
Multiple Log Files with Different Policies
# /etc/logrotate.d/multi-app
# Access logs - high volume, short retention
/var/log/multi-app/access.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0644 appuser appgroup
size 100M
}
# Error logs - keep longer
/var/log/multi-app/error.log {
weekly
rotate 12
compress
delaycompress
missingok
notifempty
create 0644 appuser appgroup
maxsize 50M
}
# Audit logs - long retention, no compression
/var/log/multi-app/audit.log {
monthly
rotate 24
nocompress
missingok
notifempty
create 0600 appuser appgroup
dateext
dateformat -%Y%m
}
Wildcard Patterns
# Rotate all logs in multiple directories
/var/log/app1/*.log /var/log/app2/*.log /var/log/app3/*.log {
daily
rotate 7
compress
missingok
notifempty
sharedscripts
postrotate
systemctl reload app-logger.service
endscript
}
# Exclude specific files
/var/log/application/*.log {
# This will rotate all .log files except debug.log
daily
rotate 5
compress
missingok
notifempty
# Use tabooext to exclude files
tabooext + .debug
}
Copy and Truncate for Open Files
# For applications that don't support log reopening
/var/log/legacy-app/app.log {
daily
rotate 7
compress
copytruncate
missingok
notifempty
# Note: copytruncate may lose some log entries
# during the copy operation
}
Compression Strategies
Using Different Compression Tools
Gzip (default):
/var/log/app/*.log {
compress
compresscmd /usr/bin/gzip
compressoptions -9
compressext .gz
}
Bzip2 (better compression, slower):
/var/log/app/*.log {
compress
compresscmd /usr/bin/bzip2
uncompresscmd /usr/bin/bunzip2
compressext .bz2
compressoptions -9
}
XZ (best compression, slowest):
/var/log/app/*.log {
compress
compresscmd /usr/bin/xz
uncompresscmd /usr/bin/unxz
compressext .xz
compressoptions -9e
}
Zstd (fast compression with good ratio):
/var/log/app/*.log {
compress
compresscmd /usr/bin/zstd
uncompresscmd /usr/bin/unzstd
compressext .zst
compressoptions -19
}
Delayed Compression Strategy
# Keep most recent rotated log uncompressed
/var/log/app/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
}
# Result:
# app.log (current, uncompressed)
# app.log.1 (yesterday, uncompressed)
# app.log.2.gz (2 days ago, compressed)
# app.log.3.gz (3 days ago, compressed)
Testing and Debugging Logrotate
Test Configuration Syntax
# Test specific configuration file
sudo logrotate -d /etc/logrotate.d/nginx
# Test main configuration
sudo logrotate -d /etc/logrotate.conf
# Verbose debug output
sudo logrotate -dv /etc/logrotate.d/myapp
Force Rotation
# Force rotation even if conditions aren't met
sudo logrotate -f /etc/logrotate.conf
# Force specific configuration
sudo logrotate -f /etc/logrotate.d/nginx
# Force with verbose output
sudo logrotate -fv /etc/logrotate.d/myapp
Manual Rotation Test
# Test rotation without updating status file
sudo logrotate -d --state /tmp/logrotate-test.status /etc/logrotate.d/myapp
# Perform actual rotation with temporary status
sudo logrotate --state /tmp/logrotate-test.status /etc/logrotate.d/myapp
Verify Rotation Results
# Check status file
sudo cat /var/lib/logrotate/status | grep myapp
# List rotated logs
ls -lht /var/log/myapp/
# Verify new log creation
ls -l /var/log/myapp/app.log
# Check log permissions
stat /var/log/myapp/app.log
Enable Logrotate Logging
# Add to /etc/logrotate.conf or specific config
/var/log/myapp/*.log {
daily
rotate 7
# Log rotation events to syslog
prerotate
logger -t logrotate "Rotating myapp logs"
endscript
postrotate
logger -t logrotate "Completed myapp log rotation"
endscript
}
# View rotation logs
sudo grep logrotate /var/log/syslog
Scheduling and Automation
Cron-Based Execution
Logrotate typically runs via cron:
# View daily cron job
cat /etc/cron.daily/logrotate
# Typical content:
#!/bin/sh
test -x /usr/sbin/logrotate || exit 0
/usr/sbin/logrotate /etc/logrotate.conf
Custom Scheduling
Run logrotate hourly:
# Create hourly script
sudo nano /etc/cron.hourly/logrotate-hourly
#!/bin/bash
/usr/sbin/logrotate /etc/logrotate.d/high-volume-app
# Make executable
sudo chmod +x /etc/cron.hourly/logrotate-hourly
Custom cron schedule:
# Edit crontab
sudo crontab -e
# Run at 3 AM daily
0 3 * * * /usr/sbin/logrotate /etc/logrotate.conf
# Run every 6 hours
0 */6 * * * /usr/sbin/logrotate /etc/logrotate.d/frequent-app
Systemd Timer
Create systemd timer for logrotate:
# Create timer unit
sudo nano /etc/systemd/system/logrotate.timer
[Unit]
Description=Daily rotation of log files
Documentation=man:logrotate(8) man:logrotate.conf(5)
[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true
[Install]
WantedBy=timers.target
Create service unit:
sudo nano /etc/systemd/system/logrotate.service
[Unit]
Description=Rotate log files
Documentation=man:logrotate(8) man:logrotate.conf(5)
ConditionACPower=true
[Service]
Type=oneshot
ExecStart=/usr/sbin/logrotate /etc/logrotate.conf
Nice=19
IOSchedulingClass=best-effort
IOSchedulingPriority=7
PrivateTmp=true
Enable and start timer:
sudo systemctl daemon-reload
sudo systemctl enable logrotate.timer
sudo systemctl start logrotate.timer
sudo systemctl status logrotate.timer
# List timer schedule
systemctl list-timers logrotate.timer
Monitoring and Alerting
Monitor Rotation Success
#!/bin/bash
# check-logrotate.sh - Monitor logrotate execution
STATUS_FILE="/var/lib/logrotate/status"
LOG_DIR="/var/log/myapp"
EMAIL="[email protected]"
# Check if rotation happened today
TODAY=$(date +%Y-%m-%d)
LAST_ROTATION=$(grep "$LOG_DIR" "$STATUS_FILE" | awk '{print $2}' | cut -d'-' -f1-3)
if [ "$LAST_ROTATION" != "$TODAY" ]; then
echo "WARNING: Logrotate may not have run today for $LOG_DIR" | \
mail -s "Logrotate Alert" "$EMAIL"
fi
# Check for old uncompressed logs
OLD_LOGS=$(find "$LOG_DIR" -name "*.log.*" -not -name "*.gz" -mtime +2)
if [ -n "$OLD_LOGS" ]; then
echo "Found old uncompressed logs: $OLD_LOGS" | \
mail -s "Logrotate Compression Issue" "$EMAIL"
fi
Disk Space Monitoring
#!/bin/bash
# monitor-log-space.sh - Alert on log directory size
LOG_DIR="/var/log"
THRESHOLD=80 # Percentage
EMAIL="[email protected]"
USAGE=$(df "$LOG_DIR" | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
{
echo "WARNING: $LOG_DIR is ${USAGE}% full"
echo ""
echo "Largest log files:"
du -sh "$LOG_DIR"/* | sort -rh | head -10
echo ""
echo "Logrotate status:"
tail -20 /var/lib/logrotate/status
} | mail -s "Log Directory Space Alert" "$EMAIL"
fi
Rotation Failure Detection
#!/bin/bash
# detect-rotation-failures.sh
# Check for failed rotations in syslog
ERRORS=$(grep logrotate /var/log/syslog | grep -i "error\|fail" | tail -10)
if [ -n "$ERRORS" ]; then
echo "Logrotate errors detected:"
echo "$ERRORS"
echo "$ERRORS" | mail -s "Logrotate Errors Detected" [email protected]
fi
# Check for very large log files (may indicate rotation failure)
find /var/log -type f -size +1G -exec ls -lh {} \; | while read line; do
echo "Large log file detected: $line"
echo "$line" | mail -s "Large Log File Alert" [email protected]
done
Troubleshooting Common Issues
Issue 1: Logrotate Not Running
Diagnosis:
# Check if logrotate is installed
which logrotate
# Verify cron daemon is running
systemctl status cron # Debian/Ubuntu
systemctl status crond # CentOS/Rocky
# Check cron job
ls -l /etc/cron.daily/logrotate
# Test manual execution
sudo /etc/cron.daily/logrotate
# Check for errors
sudo logrotate -v /etc/logrotate.conf
Solution:
# Reinstall logrotate
sudo apt install --reinstall logrotate
# Fix cron permissions
sudo chmod +x /etc/cron.daily/logrotate
# Restart cron daemon
sudo systemctl restart cron
Issue 2: Logs Not Rotating
Diagnosis:
# Check configuration syntax
sudo logrotate -d /etc/logrotate.d/myapp
# Verify log file exists
ls -l /var/log/myapp/app.log
# Check status file
sudo grep "myapp" /var/lib/logrotate/status
# Test force rotation
sudo logrotate -f /etc/logrotate.d/myapp
Common causes:
notifemptydirective with empty log- Size threshold not met
- Incorrect file path or permissions
- Syntax errors in configuration
Solution:
# Remove notifempty if log is empty
# Or ensure log has content
# Fix permissions
sudo chown root:root /etc/logrotate.d/myapp
sudo chmod 644 /etc/logrotate.d/myapp
# Correct syntax errors
sudo logrotate -d /etc/logrotate.d/myapp
Issue 3: Permission Denied Errors
Diagnosis:
# Run with verbose output
sudo logrotate -dv /etc/logrotate.d/myapp
# Check log file permissions
ls -l /var/log/myapp/
# Check logrotate process user
ps aux | grep logrotate
Solution:
# Ensure logrotate runs as root
sudo logrotate /etc/logrotate.conf
# Fix log directory permissions
sudo chmod 755 /var/log/myapp/
sudo chown myapp:myapp /var/log/myapp/*.log
# Update create directive
# In /etc/logrotate.d/myapp:
create 0644 myapp myapp
Issue 4: Compression Failing
Diagnosis:
# Check if compression tool is installed
which gzip
# Verify compression settings
sudo logrotate -dv /etc/logrotate.d/myapp | grep compress
# Check for compressed files
ls -l /var/log/myapp/*.gz
Solution:
# Install compression tool
sudo apt install gzip
# Check disk space
df -h /var/log
# Test compression manually
gzip -t /var/log/myapp/app.log.1.gz
# Remove failed compression
sudo rm /var/log/myapp/*.gz
sudo logrotate -f /etc/logrotate.d/myapp
Issue 5: Application Won't Write to New Log
Diagnosis:
# Check if new log file was created
ls -l /var/log/myapp/app.log
# Verify permissions
stat /var/log/myapp/app.log
# Check application process
lsof | grep app.log
Solution:
# Use copytruncate for applications that can't reopen logs
/var/log/myapp/app.log {
copytruncate
daily
rotate 7
}
# Or add postrotate script to reload application
postrotate
systemctl reload myapp.service
endscript
# Or send signal to reopen logs
postrotate
kill -HUP $(cat /var/run/myapp.pid)
endscript
Best Practices
Configuration Organization
# 1. Use separate config files per application
/etc/logrotate.d/nginx
/etc/logrotate.d/mysql
/etc/logrotate.d/myapp
# 2. Use descriptive filenames
/etc/logrotate.d/application-access-logs
/etc/logrotate.d/application-error-logs
# 3. Document unusual configurations
# /etc/logrotate.d/myapp
# Special rotation for high-volume application
# Rotates hourly via cron.hourly instead of daily
/var/log/myapp/*.log {
size 100M
rotate 24
compress
}
Security Considerations
# Secure configuration files
sudo chmod 644 /etc/logrotate.d/*
sudo chown root:root /etc/logrotate.d/*
# Restrict log access
create 0640 appuser appgroup
# Don't email sensitive logs
nomail
# Use secure old directory
olddir /var/log/secure-archive
create 0600 root root
Performance Optimization
# Use delayed compression for frequently accessed logs
delaycompress
# Compress in background for large files
compress
compressoptions -1 # Fast compression
# Use sharedscripts to reduce overhead
sharedscripts
postrotate
systemctl reload nginx
endscript
# Limit rotation frequency for high-volume logs
size 500M
maxsize 1G
Retention Policies
# Short-term high-volume logs
/var/log/app/access.log {
daily
rotate 7
maxage 7
}
# Medium-term error logs
/var/log/app/error.log {
weekly
rotate 12
maxage 90
}
# Long-term audit logs
/var/log/app/audit.log {
monthly
rotate 24
maxage 730
nocompress
}
Conclusion
Logrotate is an essential tool for maintaining a healthy logging infrastructure on Linux systems. Proper configuration ensures that logs are rotated efficiently, disk space is managed effectively, and historical data is retained according to your requirements.
Key takeaways:
- Automated management - Logrotate handles the complete lifecycle of log files without manual intervention
- Flexible policies - Configure rotation based on time, size, or both to match your application needs
- Compression strategies - Balance disk space savings with access requirements using appropriate compression
- Application integration - Use pre/postrotate scripts to ensure applications handle log rotation correctly
- Monitoring - Regularly verify that rotation is working as expected and disk space is under control
By implementing the configurations and practices outlined in this guide, you'll maintain manageable log files, prevent disk space issues, ensure compliance with retention requirements, and facilitate efficient log analysis when troubleshooting issues or investigating security incidents.
Remember to test your logrotate configurations thoroughly before deploying to production, monitor rotation execution regularly, and adjust retention policies as your storage capacity and compliance requirements evolve.


