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:
- External rotation — using a system tool like
logrotatethat runs on a schedule and reloads Apache afterward (covered in my other post). - Native/piped rotation — using Apache’s own
rotatelogsbinary (or third-partycronolog) directly in theCustomLog/ErrorLogdirective, 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?
- No reload needed — since Apache pipes output directly to the rotation tool, there’s no need to reload the service to “reopen” log handles after rotation.
- Precise timing —
rotatelogscan split logs by exact time intervals or size thresholds, independent of cron schedules. - Good for high-traffic servers — where logrotate’s daily/weekly cron-based approach might not be granular enough.
Prerequisites
- Apache installed with
mod_log_config(enabled by default) - The
rotatelogsbinary, which ships with Apache (usually at/usr/sbin/rotatelogsor/usr/bin/rotatelogs) - Root or sudo access to edit Apache configuration
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:
- The leading
|tells Apache to pipe log output to an external command instead of writing directly to a file. %Y-%m-%dis a strftime-style timestamp pattern, so each day gets its own uniquely named log file.86400is the rotation interval in seconds (in this case, 24 hours).
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:
- logrotate — my default choice for the vast majority of setups. It’s already installed on nearly every Linux distribution, well understood, and handles compression and cleanup out of the box.
- rotatelogs/cronolog — reserved for high-traffic servers where I need rotation more frequent than daily, or where I want rotation independent of any cron schedule.
- Manual scripts — only for minimal, embedded, or highly customized environments where I want full control and don’t want to depend on external packages.
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
- Forgetting the leading pipe
|in the CustomLog directive — without it, Apache tries to write to a literal file named/usr/sbin/rotatelogs...instead of piping to the program. - Not testing config changes before restarting — a broken piped logging directive can prevent Apache from starting entirely.
- Mixing logrotate and rotatelogs on the same file — this causes conflicts, since both tools try to manage rotation independently. Pick one approach per log file.
- Not handling compression/cleanup separately —
rotatelogsandcronologonly split files; they don’t compress or delete old ones automatically.
Security Best Practices
- Ensure rotated log files retain proper permissions (
640, owned by an appropriate user/group) since the piping process may create files with different default permissions than expected. - Regularly clean up old rotated logs to avoid retaining sensitive data (IPs, query strings) longer than necessary for compliance.
- Restrict access to log directories so only authorized administrators can read them.
Performance Optimization Tips
- Use time-based rotation (hourly or daily) for high-traffic servers to keep individual log files small and fast to search.
- Combine piped rotation with a separate compression/cleanup cron job rather than trying to do everything in one tool.
- Avoid setting rotation intervals so short that you generate an excessive number of tiny files, which can complicate log analysis tools like AWStats or Logwatch.
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.