How to Use Logrotate to Manage Apache Logs

How to use logrotate to manage Apache logs

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 (apache2 or httpd)
  • logrotate installed (it comes pre-installed on most distributions, but you can check with logrotate --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 copytruncate unnecessarily — 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 -d first — pushing an untested config to production can silently break log rotation for months.

Security Best Practices

  • Set correct file permissions (640 is 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 compress combined with delaycompress to balance disk savings against CPU usage during rotation.
  • For very high-traffic servers, consider size directives 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.

References

Total
1
Shares

Leave a Reply

Previous Post
How to troubleshoot common Apache log errors

How to troubleshoot common Apache log errors

Next Post
How to generate a self-signed SSL certificate for Apache

How to Generate a Self-Signed SSL Certificate for Apache

Related Posts