One of the things I overlooked early in my sysadmin days was log management. I’d spin up an Apache server, forget about it for six months, and come back to find /var/log/apache2/access.log had ballooned to several gigabytes, eating up disk space and slowing down anything that tried to read it. That’s when I started using logrotate seriously, and I want to walk you through exactly how I set it up.
What Is Logrotate?
Logrotate is a Linux utility that automates the rotation, compression, removal, and mailing of log files. Instead of letting a single log file grow forever, logrotate periodically renames the current log, starts a fresh one, and optionally compresses or deletes older versions based on rules you define.
For Apache, this matters a lot because access.log and error.log can grow extremely fast on busy sites — sometimes hundreds of megabytes per day.
Why Log Rotation Matters
- Disk space management — unrotated logs can fill up a disk and crash your server.
- Performance — tools that parse logs (like AWStats or Logwatch) run much faster on smaller files.
- Compliance — many organizations require logs to be retained for a specific period and then securely discarded.
- Easier troubleshooting — smaller, dated log files are easier to search through than one giant file.
Prerequisites
- A Linux server running Apache (
apache2orhttpd) logrotateinstalled (it comes pre-installed on most distributions, but you can check withlogrotate --version)- Root or sudo access
Step 1: Confirm Logrotate Is Installed
logrotate --version
If it’s missing, install it:
# Debian/Ubuntu
sudo apt install logrotate -y
# CentOS/RHEL
sudo yum install logrotate -y
Step 2: Locate Apache’s Existing Logrotate Configuration
Most Apache installations already ship with a default logrotate config. You’ll find it at:
/etc/logrotate.d/apache2 # Debian/Ubuntu
/etc/logrotate.d/httpd # CentOS/RHEL
Let’s look at what a typical default looks like:
cat /etc/logrotate.d/apache2
/var/log/apache2/*.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
if invoke-rc.d apache2 status > /dev/null 2>&1; then \
invoke-rc.d apache2 reload > /dev/null; fi;
endscript
}
This is a solid starting point, but I usually customize it depending on traffic volume and retention requirements.
Step 3: Understanding Each Directive
Here’s what each line actually does, since understanding this is key to customizing it properly:
weekly— rotate logs once a week (other options:daily,monthly,yearly).missingok— don’t throw an error if the log file is missing.rotate 52— keep 52 rotated copies (a year’s worth of weekly logs).compress— gzip old log files to save space.delaycompress— delay compression until the next rotation cycle (so the most recently rotated file stays uncompressed and readable by tools that might still be writing to it).notifempty— don’t rotate if the log file is empty.create 640 root adm— after rotation, create a new empty log file with these permissions and ownership.sharedscripts— run the postrotate script once for all logs, not once per file.postrotate...endscript— commands to run after rotation; here, it reloads Apache so it starts writing to the new log file.
Step 4: Customizing for High-Traffic Sites
If you’re running a busy site, weekly rotation isn’t enough — the file will get huge before it even rotates. I switch to daily rotation with size-based limits:
/var/log/apache2/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
size 100M
postrotate
systemctl reload apache2 > /dev/null 2>/dev/null || true
endscript
}
Here I added size 100M, which forces a rotation whenever the log hits 100MB, regardless of the schedule. This is critical for e-commerce sites or anything under heavy load.
Step 5: Testing Your Configuration
Before trusting logrotate to run unattended, always test it manually:
sudo logrotate -d /etc/logrotate.d/apache2
The -d flag runs in debug mode, showing you what would happen without actually rotating anything.
To force an actual rotation for testing:
sudo logrotate -f /etc/logrotate.d/apache2
Check the log directory afterward:
ls -lh /var/log/apache2/
You should see files like access.log, access.log.1.gz, access.log.2.gz, and so on.
Step 6: Verify the Cron Job
Logrotate itself runs via cron, typically triggered daily by a system cron job at /etc/cron.daily/logrotate. You can confirm it’s scheduled:
cat /etc/cron.daily/logrotate
If your distribution uses systemd timers instead:
systemctl list-timers | grep logrotate
Real-World Use Case: Rotating Logs for Multiple Virtual Hosts
If you’re hosting multiple sites, each with its own log files, I recommend a per-site logrotate config so you can tune retention independently:
/var/log/apache2/site1-access.log /var/log/apache2/site1-error.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 www-data adm
sharedscripts
postrotate
systemctl reload apache2 > /dev/null 2>/dev/null || true
endscript
}
I place each of these in its own file inside /etc/logrotate.d/ for clarity, like site1-apache and site2-apache.
Understanding the Logrotate State File
One thing that confused me early on was how logrotate “remembers” what it’s already rotated. It tracks this in a state file, usually located at:
/var/lib/logrotate/status
Each entry looks like this:
"/var/log/apache2/access.log" 2026-7-25-2:0:0
This tells logrotate the last time it processed that specific file, which is how it knows whether a daily, weekly, or monthly rotation is actually due. If you ever need to force logrotate to treat a file as “never rotated” (for testing), you can remove its entry from this file, or simply use the -f flag to force rotation regardless of the recorded state.
Handling Logs Across Multiple Apache Instances
If you’re running multiple Apache instances on one machine (common in shared hosting or multi-tenant setups), I create separate logrotate configuration blocks per instance rather than lumping everything into a wildcard pattern. This gives me independent retention policies per site and avoids one massive log directory becoming a single point of confusion during an incident.
/var/log/apache2/tenant-a/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
systemctl reload apache2 > /dev/null 2>/dev/null || true
endscript
}
/var/log/apache2/tenant-b/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
systemctl reload apache2 > /dev/null 2>/dev/null || true
endscript
}
This lets tenant A keep 30 days of history while tenant B, which might have stricter storage constraints, only keeps 7.
Integrating Logrotate with Off-Server Archival
For compliance-heavy environments, I don’t just let compressed logs pile up locally forever — I ship them off to cold storage. A simple approach is adding a lastaction script that syncs recently rotated, compressed logs to an S3 bucket or a remote backup server:
/var/log/apache2/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
systemctl reload apache2 > /dev/null 2>/dev/null || true
endscript
lastaction
aws s3 sync /var/log/apache2/ s3://my-log-archive-bucket/apache2/ --exclude "*" --include "*.gz"
endscript
}
This keeps only two weeks of logs locally while retaining a much longer history remotely for audits or historical investigations.
Common Mistakes I’ve Made
- Forgetting
sharedscripts— without it, Apache gets reloaded once per log file, which is wasteful and can cause brief service hiccups. - Skipping the postrotate reload — Apache keeps writing to the old (now renamed) file handle until it’s told to reopen logs, so without a reload, your “new” log file stays empty.
- Using
copytruncateunnecessarily — this creates a small race condition where a few log lines can be lost between the copy and truncate operations. I only use it when I can’t restart the service. - Not testing with
-dfirst — pushing an untested config to production can silently break log rotation for months.
Security Best Practices
- Set correct file permissions (
640is a common default) so logs aren’t world-readable, since they can contain IP addresses and sometimes sensitive query strings. - Store rotated logs in a directory with restricted access, and consider shipping them to a centralized log server for long-term retention and auditing.
- If compliance requires it, encrypt archived logs before moving them off-server.
Performance Optimization Tips
- Use
compresscombined withdelaycompressto balance disk savings against CPU usage during rotation. - For very high-traffic servers, consider
sizedirectives to prevent any single log from growing unmanageably large between scheduled rotations. - Offload old, compressed logs to cheaper storage (like an object storage bucket) via a scheduled script, rather than keeping years of logs on your primary disk.
Troubleshooting Common Issues
Logs aren’t rotating at all — check /var/lib/logrotate/status (or /var/lib/logrotate.status on older systems) to see the last rotation timestamp for each log file.
New log file isn’t being written to after rotation — this almost always means the postrotate script didn’t reload Apache properly. Test the reload command manually.
Permission denied errors during rotation — double check the create directive’s user and group match what Apache expects (www-data on Debian, apache on RHEL).
FAQs
How often should I rotate Apache logs? For low-traffic sites, weekly is fine. For high-traffic sites, daily or size-based rotation is safer.
Will rotating logs interrupt my website? No, as long as the postrotate script correctly reloads Apache so it reopens its log file handles.
How long should I keep rotated logs? It depends on your compliance and troubleshooting needs. I typically keep 14–30 days of daily logs, or up to a year for weekly logs on lower-traffic sites.
Can I compress logs immediately instead of delaying it? Yes, just remove delaycompress, but I recommend keeping it since some tools may still be reading the most recently rotated file.
Summary and Key Takeaways
Logrotate is one of those unglamorous but essential tools that keeps your Apache server healthy long-term. By configuring rotation frequency, retention count, compression, and a proper postrotate reload, you avoid disk space issues and keep your logs organized and easy to analyze. I recommend testing any config changes with logrotate -d before relying on them in production.