How to Rotate Apache Logs

How to rotate Apache logs

How to rotate Apache logs

I’ve already written about using logrotate to manage Apache logs, but I get asked often about the other ways to rotate logs — particularly Apache’s own built-in rotatelogs utility and third-party tools like cronolog. In this post, I want to cover log rotation more broadly, including these native approaches, so you can pick the method that fits your setup.

What Does “Rotating Logs” Actually Mean?

Log rotation is the process of archiving a current log file, starting a fresh one, and eventually compressing or deleting old archives based on retention rules. Without rotation, a single Apache log file grows indefinitely, eventually consuming disk space and becoming unwieldy to search through.

There are two broad approaches for Apache specifically:

  1. External rotation — using a system tool like logrotate that runs on a schedule and reloads Apache afterward (covered in my other post).
  2. Native/piped rotation — using Apache’s own rotatelogs binary (or third-party cronolog) directly in the CustomLog/ErrorLog directive, so Apache itself pipes log output through the rotation tool in real time.

This post focuses mainly on the second approach, since it’s less commonly covered but extremely useful for high-traffic servers where waiting for an external cron job isn’t ideal.

Why Consider Native/Piped Log Rotation?

Prerequisites

Step 1: Locate the rotatelogs Binary

which rotatelogs

If it’s missing, it’s typically included in the apache2-utils (Debian/Ubuntu) or httpd-tools (CentOS/RHEL) package:

sudo apt install apache2-utils -y
# or
sudo yum install httpd-tools -y

Step 2: Configure Piped Logging in Your Virtual Host

Instead of a standard CustomLog pointing directly to a file, you pipe the output through rotatelogs:

CustomLog "|/usr/sbin/rotatelogs /var/log/apache2/access.log.%Y-%m-%d 86400" combined
ErrorLog "|/usr/sbin/rotatelogs /var/log/apache2/error.log.%Y-%m-%d 86400"

Here’s what’s happening:

Step 3: Rotating by Size Instead of Time

rotatelogs also supports size-based rotation using the -l flag combined with a byte threshold:

CustomLog "|/usr/sbin/rotatelogs -l /var/log/apache2/access.log.%Y-%m-%d 100M" combined

This rotates whenever the log reaches 100MB, regardless of elapsed time. The -l flag tells rotatelogs to use local time rather than UTC when naming files.

Step 4: Restart Apache to Apply Changes

sudo apache2ctl configtest
sudo systemctl restart apache2

Always run configtest first — a malformed piped logging directive can prevent Apache from starting.

Step 5: Verify Rotation Is Working

ls -lh /var/log/apache2/

You should see files like:

access.log.2026-07-25
access.log.2026-07-26
error.log.2026-07-25
error.log.2026-07-26

Using cronolog as an Alternative

Some admins prefer cronolog over rotatelogs for its slightly more flexible template syntax and additional symlink features. Install it:

sudo apt install cronolog -y

Configure it similarly:

CustomLog "|/usr/sbin/cronolog /var/log/apache2/%Y/%m/%d/access.log" combined
ErrorLog "|/usr/sbin/cronolog /var/log/apache2/%Y/%m/%d/error.log"

Notice cronolog supports full directory hierarchies based on the date pattern, automatically creating /var/log/apache2/2026/07/26/access.log, for example — handy for very long-term log organization.

Combining Piped Rotation with Compression and Cleanup

Since rotatelogs and cronolog only handle the splitting of logs — not compression or deletion of old files — I usually pair them with a simple cron job for cleanup:

sudo crontab -e
0 2 * * * find /var/log/apache2/ -name "access.log.*" -mtime +30 -exec gzip {} \;
0 3 * * * find /var/log/apache2/ -name "*.gz" -mtime +90 -delete

This compresses logs older than 30 days and deletes compressed logs older than 90 days.

Real-World Use Case: High-Traffic API Server

I once managed an API server processing tens of millions of requests a day. Waiting for a nightly logrotate cron job meant a single day’s log could exceed 5GB, making analysis painfully slow. Switching to rotatelogs with hourly rotation (3600 seconds) kept individual files small and immediately searchable, and gave us much finer-grained data for correlating incidents to specific hours.

CustomLog "|/usr/sbin/rotatelogs /var/log/apache2/access.log.%Y-%m-%d-%H 3600" combined

Rotating Logs Manually with a Script (No External Tools)

Occasionally I work on minimal systems where I’d rather not install logrotate, rotatelogs, or cronolog at all. In those cases, I write a simple manual rotation script using standard shell commands:

#!/bin/bash
LOG_DIR="/var/log/apache2"
DATE=$(date +%Y-%m-%d)

for log in access.log error.log; do
    if [ -f "$LOG_DIR/$log" ]; then
        mv "$LOG_DIR/$log" "$LOG_DIR/$log.$DATE"
        gzip "$LOG_DIR/$log.$DATE"
    fi
done

systemctl reload apache2

The critical step here is the reload at the end — since Apache holds an open file descriptor to the original log file, simply renaming it doesn’t stop Apache from writing to it. A reload forces Apache to close and reopen its log files, causing it to create a fresh access.log and error.log at the original path. Without this step, your “rotated” file just keeps growing under its new name, defeating the purpose entirely.

Choosing Between the Three Approaches

After years of managing Apache logs across different environments, here’s how I decide which method to use:

For the overwhelming majority of readers, logrotate remains the right first choice, and I’d only reach for the alternatives covered here once a specific limitation of the cron-based approach becomes a real problem.

Common Mistakes I’ve Made

Security Best Practices

Performance Optimization Tips

Troubleshooting Common Issues

Apache won’t start after adding piped logging — run apache2ctl configtest to check for syntax errors, and verify the path to rotatelogs or cronolog is correct.

Log files aren’t being created — check permissions on the target log directory; the user Apache runs as needs write access, and so does the piped process.

Old rotated logs never get cleaned up — remember that rotatelogs/cronolog don’t handle compression or deletion; you need a separate cron job for that.

FAQs

Should I use logrotate or rotatelogs? For most standard setups, logrotate is simpler and sufficient. I reach for rotatelogs or cronolog specifically for high-traffic servers needing finer-grained, real-time rotation without waiting for a scheduled cron job.

Can I use both logrotate and rotatelogs together? Not on the same log file — they’ll conflict. Pick one method per log file to avoid confusion and potential data loss.

Does rotatelogs compress old logs automatically? No, you need a separate script or cron job to gzip old files.

What rotation interval should I use? For most sites, daily rotation is plenty. For very high-traffic servers, hourly rotation keeps files more manageable and easier to search quickly.

Summary and Key Takeaways

While logrotate is the standard, cron-driven way to manage Apache logs, piped rotation tools like rotatelogs and cronolog give you more precise, real-time control — particularly valuable for high-traffic servers where daily rotation isn’t granular enough. Whichever method you choose, remember to pair it with a separate compression and cleanup strategy, and never mix both rotation methods on the same log file.

References

Exit mobile version