Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Log Rotation and Disk Space Management on Linux

By Kokil Thapa | Last reviewed: September 2026

A full root partition at 3 a.m. is one of the fastest ways to take down a live site. Log rotation and disk space management on Linux exist to stop that failure mode before it starts. Application logs, web server access logs, database binary logs, and systemd journals all grow without bound unless you cap them. On production Ubuntu servers I maintain for Linux system administration clients, disk-full incidents from logs still rank among the top preventable outages. This guide covers the tools, configs, and commands that actually work in 2026.

What causes disk space problems from logs on Linux servers?

Logs are append-only by design. Every HTTP request, PHP error, cron run, and database write can add lines to disk. The problem compounds quietly. A busy Laravel app behind Apache can generate hundreds of megabytes of access logs per day. MySQL binary logs on a replication host can grow into tens of gigabytes if nobody trims them.

Three categories dominate disk consumption on web servers:

  • System and service logs — syslog, auth.log, kern.log, and journald entries under /var/log and /var/log/journal
  • Web stack logs — Apache or Nginx access and error logs, PHP-FPM slow logs, application logs in storage/logs
  • Database and backup artefacts — MySQL binary logs, PostgreSQL WAL segments, stale SQL dumps left in /tmp or /home

I've seen a legal-tech portal lose its booking form because /var hit 100% capacity. Apache could not write error logs, PHP sessions failed, and MySQL rejected writes. The fix took ten minutes once we found the culprit. Prevention would have cost zero.

Linux Log Sources and Disk Fill RiskWeb ServerApache / NginxApplicationLaravel / PHPDatabaseMySQL binlogssystemd journal/var/loggrows dailyDisk 100%services failPrevention: logrotate + journald limitsmonitor with df, du, and alerts
Log rotation and disk space management on Linux — unchecked logs flow from services into /var and can fill partitions until applications crash.

Understanding where logs land is step one. Step two is enforcing retention before the partition turns red. That split between discovery and policy is what separates stable servers from pager-duty weekends.

How does logrotate handle log rotation on Linux?

logrotate is the standard rotation engine on Debian and Ubuntu. It runs daily via cron or a systemd timer. It reads global rules from /etc/logrotate.conf and per-service snippets from /etc/logrotate.d/.

A typical rotation cycle does four things:

  1. Renames the active log file (for example access.log becomes access.log.1)
  2. Optionally compresses older files with gzip
  3. Creates a fresh empty log file with correct ownership
  4. Signals the service to reopen log handles via postrotate scripts

Global defaults in /etc/logrotate.conf

Ubuntu ships sensible defaults. Most custom configs inherit from them:

weekly
rotate 4
create
include /etc/logrotate.d

That means four weekly rotations before deletion unless a snippet overrides the schedule. For high-traffic web servers, weekly is too slow. Daily rotation with a size trigger is safer.

Apache logrotate example

On servers running Apache with PHP-FPM 8.3 or 8.4, I use a dedicated snippet at /etc/logrotate.d/apache2-custom:

/var/log/apache2/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 640 root adm
    sharedscripts
    postrotate
        systemctl reload apache2 > /dev/null 2>&1 || true
    endscript
}

Key directives explained:

  • daily — rotate every day, not weekly
  • rotate 14 — keep fourteen archived files (~two weeks)
  • compress / delaycompress — gzip old logs but leave yesterday's uncompressed for easy tailing
  • postrotate — reload Apache so it writes to the new file handle

Without postrotate, Apache keeps writing to the renamed inode. The new access.log stays empty while the rotated file keeps growing. That is a classic misconfiguration I still find on inherited servers.

Laravel application logs

Laravel writes to storage/logs/laravel.log by default. Framework logs are not covered by system logrotate unless you add them. For Deployer-managed releases on sites like Notary Kathmandu, the log path lives in the shared storage directory:

/var/www/example.com/shared/storage/logs/*.log {
    daily
    size 50M
    rotate 7
    compress
    missingok
    notifempty
    copytruncate
}

copytruncate copies the log then truncates the original in place. Laravel and PHP-FPM do not need a reload signal. The trade-off is a small race window during copy. For most apps under moderate load, that is acceptable.

For structured application logging patterns in Laravel itself, see the guide on Laravel activity log with Spatie. Application-level audit trails and server-level rotation solve different problems. You need both on compliance-sensitive portals.

logrotate Daily CycleCron timerRead configsCheck sizeRotateFile rename chainaccess.logactive file.log.1yesterday.log.2.gzcompresseddeletedpast rotate Npostrotate reloads Apache / Nginx
How logrotate renames, compresses, and deletes old log files during its scheduled run on Linux.

Test any new config before trusting it:

sudo logrotate -d /etc/logrotate.d/apache2-custom
sudo logrotate -f /etc/logrotate.d/apache2-custom

The -d flag dry-runs with verbose output. The -f flag forces an immediate rotation. Run both after every config change.

How do you manage systemd journal disk usage?

Modern Ubuntu servers store a large share of logs in the systemd journal, not plain files. The journal lives under /var/log/journal and can balloon silently. journald has its own retention controls separate from logrotate.

Check current journal size:

journalctl --disk-usage

Set limits in /etc/systemd/journald.conf:

[Journal]
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=30day
Compress=yes

Apply changes:

sudo systemctl restart systemd-journald

One-time cleanup for emergencies:

sudo journalctl --vacuum-size=200M
sudo journalctl --vacuum-time=14d

On shared EC2 hosts where multiple Laravel sites run under one account, I cap the journal at 500 MB. That leaves headroom for Apache logs and MySQL data on a 40 GB root volume. Budget-conscious hosting setups in Nepal often use modest VPS disks. Journal limits are not optional there.

Which tools find what is consuming disk space on Linux?

Rotation policies fail if you never look at disk usage. These commands belong in every admin's toolkit and in scheduled monitoring scripts.

Partition-level check

df -hT
df -h /var

Watch the Use% column on /var, /, and any separate /home or /data mounts. Above 85% warrants investigation. Above 95% is an incident.

Directory-level drill-down

sudo du -xh /var --max-depth=1 | sort -hr | head -20
sudo du -xh /var/log --max-depth=1 | sort -hr | head -20

Find individual monster files:

sudo find /var/log -type f -size +100M -exec ls -lh {} \;
sudo lsof +L1

lsof +L1 finds deleted files still held open by processes. The disk space is not freed until the process restarts. That happens after a logrotate without postrotate, or when a developer deletes a log manually while Apache keeps the handle.

Compare log management approaches

ToolLog typeBest forConfig location
logrotatePlain text filesApache, Nginx, PHP, app logs/etc/logrotate.d/
journaldBinary systemd journalService stdout, kernel, auth/etc/systemd/journald.conf
MySQL expire_logs_daysBinary replication logsMySQL 8.4 replication hostsmy.cnf or SET GLOBAL
Application loggerStructured app logsLaravel Monolog channelsconfig/logging.php
Central aggregationShipped remote logsMulti-server fleetsLoki, Fluent Bit agents

For multi-server setups, file rotation alone is not enough. You also need shipping and central retention. The guides on log aggregation with Loki and Grafana and log aggregation for small teams cover that next step. On a single VPS running WooCommerce or a law-firm portal, local logrotate plus journald caps solve 90% of cases.

logrotate vs journaldlogrotatePlain text files/var/log/apache2/Size + time triggersgzip compressionpostrotate reloadWeb + app logsjournaldBinary journal/var/log/journal/SystemMaxUse capjournalctl queriesvacuum cleanupsystemd servicesUse both together on production Ubuntu servers
logrotate and journald serve different log types — effective disk space management on Linux requires configuring both.

Rotation configs are static. Traffic is not. A viral blog post or brute-force auth storm can produce a week's worth of logs in hours. Automation closes that gap.

Cron-based disk checks

A simple guard script in /usr/local/bin/check-disk.sh:

#!/bin/bash
THRESHOLD=85
USAGE=$(df /var --output=pcent | tail -1 | tr -dc '0-9')
if [ "$USAGE" -ge "$THRESHOLD" ]; then
  du -xh /var/log --max-depth=1 | sort -hr | head -10 > /tmp/disk-alert.txt
  mail -s "Disk alert: /var at ${USAGE}%" admin@example.com < /tmp/disk-alert.txt
fi

Schedule it via cron. For systemd timer alternatives, see cron jobs explained and systemd service management.

MySQL binary log rotation

Replication and point-in-time recovery need binary logs. Uncapped binlogs have filled more disks than Apache ever did. On MySQL 8.4 LTS hosts:

expire_logs_days = 7
max_binlog_size = 100M

Verify with:

SHOW BINARY LOGS;
PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 7 DAY);

The dedicated guide on MySQL binary logs for replication and backup goes deeper. Binlog retention and automated database backups must be planned together. Purging logs you have not backed up destroys recovery options.

Monitoring with alerts

Netdata, Prometheus node_exporter, or a simple Nagios check on disk percentage all work. I prefer alerting at 80% with a top-ten /var/log breakdown included in the notification. That gives you time to act before writes fail. Read the setup walkthrough for Linux server monitoring with Netdata if you want a lightweight agent on Ubuntu 24.04.

PHP-FPM and opcache log paths

PHP-FPM slow logs and error logs live outside Apache's rotation scope unless configured. Add /var/log/php8.3-fpm.log or your pool-specific paths to logrotate. After Deployer symlink swaps on Adventure Third Pole Trek and sister sites, verify that shared log paths still match your rotation snippets. A changed release path silently breaks coverage.

For ongoing server hygiene beyond logs, support and maintenance contracts typically include disk audits, rotation reviews, and backup verification. Logs are one slice of a wider reliability picture that also covers testing and optimization work.

Prevent Disk-Full IncidentsConfigurelogrotateCap journald500M limitMonitor df80% alertDaily: logrotate runs automaticallyWeekly: review du -sh /var/log manuallyDisk healthyunder 85%Alert firesdu + vacuumPair with database backup and log shipping policies
Automated log rotation and disk space management on Linux — configure retention, monitor usage, and respond before services fail.

Log analysis without filling disk

SEO log file analysis for crawl diagnostics can tempt teams to retain months of raw access logs. That is valid for insight but expensive on disk. For technical SEO work, see SEO log file analysis. Rotate aggressively locally and ship compressed archives to object storage if you need long retention.

When parsing large JSON log exports locally, the JSON formatter tool helps inspect individual entries without loading them into a spreadsheet. It does not replace rotation policy, but it speeds up incident triage.

Key Takeaways

  • Configure logrotate for every custom log path — Apache, PHP-FPM, Laravel storage/logs, and MySQL slow query logs are not always covered by defaults.
  • Cap systemd journal size with SystemMaxUse in journald.conf; run journalctl --vacuum-size after emergencies.
  • Always include postrotate reload scripts for Apache and Nginx, or use copytruncate for apps that cannot signal log reopen.
  • Monitor /var at 80–85% with automated alerts that include a du breakdown of /var/log top consumers.
  • Set MySQL binary log expiry explicitly; binlogs are a common hidden cause of full disks on replication hosts.
  • Test configs with logrotate -d before deployment, and audit rotation coverage after every deployment path change.

People Also Ask

How often should logs rotate on a production web server?

Daily rotation is the baseline for Apache and Nginx access logs on any site with meaningful traffic. Add a size trigger (for example size 100M) so a traffic spike rotates early instead of waiting until midnight. Keep 7–14 compressed archives depending on compliance needs and available disk.

What happens if I delete a log file while the service is running?

The disk space is not freed. The process holds an open file descriptor to the deleted inode and keeps writing to it. Use logrotate with postrotate, or truncate with copytruncate, or restart the service. Check orphaned handles with lsof +L1.

Can logrotate compress logs automatically?

Yes. Add compress and delaycompress to any logrotate stanza. gzip reduces archived logs by 80–95% for typical text access logs. delaycompress skips compressing the most recent archive so you can tail yesterday's file without gunzip.

Is journald or logrotate enough on its own?

No. journald manages systemd's binary journal only. Apache, Nginx, PHP, Laravel, and MySQL write plain files that logrotate must handle separately. Production servers need both tools configured with explicit retention limits.

Build reliable servers before logs take them down

Log rotation and disk space management on Linux is not glamorous work. It is the kind of boring infrastructure that keeps Laravel booking apps, WooCommerce stores, and legal portals online when traffic spikes. Configure logrotate snippets, cap journald, expire MySQL binlogs, and alert on disk usage before you need emergency cleanup at 3 a.m.

If your production server has never had a rotation audit, assume gaps exist. For hands-on help configuring Ubuntu servers, rotation policies, and monitoring on sites you depend on, see the Linux system administration service or review deployed work in the portfolio. Need a full reliability review across hosting, backups, and logs? Contact us to discuss your server setup.

Frequently Asked Questions

Logs are append-only, so every HTTP request, PHP error, cron run, and database write adds lines to disk without automatic cleanup. On busy web servers, Apache access logs, systemd journals under /var/log/journal, PHP-FPM slow logs, Laravel storage/logs output, and MySQL binary logs on replication hosts are the usual culprits. The problem compounds quietly until /var or root hits 100%, at which point Apache cannot write errors, PHP sessions fail, and MySQL rejects writes. I've seen a legal-tech portal lose its booking form this way. Understanding where each service writes logs is the first step toward preventing it.

logrotate is the standard rotation engine on Debian and Ubuntu. It runs daily via cron or a systemd timer, reads /etc/logrotate.conf and snippets in /etc/logrotate.d/, renames active logs, optionally gzip-compresses older files, creates fresh empty logs with correct ownership, and signals services via postrotate scripts to reopen file handles. Without that reload step, services keep writing to the renamed inode and the new log file stays empty while the old one keeps growing.

Daily rotation is the baseline for Apache and Nginx access logs on any site with meaningful traffic. Add a size trigger such as size 100M so traffic spikes rotate early instead of waiting until midnight. Keep seven to fourteen compressed archives depending on compliance needs and available disk.

Global defaults live in /etc/logrotate.conf, which typically sets weekly rotation, four rotations before deletion, and includes /etc/logrotate.d/. Per-service snippets go in that directory — for example /etc/logrotate.d/apache2-custom for Apache or a dedicated stanza for Laravel logs under shared/storage/logs on Deployer-managed sites. High-traffic web servers should override the default weekly schedule with daily rotation and explicit rotate counts. Always test new snippets with logrotate -d before trusting them in production.

The disk space is not freed. The process holds an open file descriptor to the deleted inode and keeps writing to it. Use logrotate with a postrotate reload, truncate with copytruncate, or restart the service. Check orphaned handles with lsof +L1.

After logrotate renames access.log to access.log.1 and creates a new empty file, Apache still holds the old file handle open. Without postrotate running systemctl reload apache2, Apache continues writing to the renamed inode. The new access.log stays empty while the rotated file keeps growing — a classic misconfiguration I still find on inherited servers. The postrotate block tells Apache to reopen its log handles so writes land in the fresh file. The same principle applies to Nginx reloads.

Laravel writes to storage/logs/laravel.log by default, and framework logs are not covered by system logrotate unless you add them. On Deployer-managed releases, the path lives in the shared storage directory. Add a snippet like /var/www/example.com/shared/storage/logs/*.log with daily rotation, size 50M, rotate 7, compress, and copytruncate. copytruncate copies then truncates in place so PHP-FPM and Laravel need no reload signal. There is a small race window during copy, but it is acceptable for most apps under moderate load.

Modern Ubuntu servers store much of their logging in the binary journal under /var/log/journal, which balloon silently without caps. Check current size with journalctl --disk-usage, then set limits in /etc/systemd/journald.conf — for example SystemMaxUse=500M, SystemKeepFree=1G, MaxRetentionSec=30day, and Compress=yes. Apply with systemctl restart systemd-journald. For emergencies, run journalctl --vacuum-size=200M or journalctl --vacuum-time=14d. On shared EC2 hosts with modest VPS disks, journal limits are not optional.

No. journald manages systemd's binary journal only — service stdout, kernel messages, and auth entries stored under /var/log/journal. Apache, Nginx, PHP-FPM, Laravel, and MySQL write plain text or binary files that logrotate or database settings must handle separately. Production servers need both tools configured with explicit retention limits. On a single VPS running WooCommerce or a law-firm portal, local logrotate plus journald caps solve roughly ninety percent of cases, but skipping either leaves a blind spot.

Start partition-level with df -hT and watch the Use% column on /var and root — above eighty-five percent warrants investigation, above ninety-five percent is an incident. Drill down with du -xh /var --max-depth=1 sorted by size, or du -xh /var/log --max-depth=1 for log-specific breakdowns. Find individual large files with find /var/log -type f -size +100M. If rotation ran but space did not drop, check lsof +L1 for deleted files still held open by running processes — common after logrotate without postrotate or manual log deletion.

Yes. Add compress and delaycompress to any logrotate stanza. gzip reduces archived text access logs by eighty to ninety-five percent. delaycompress skips compressing the most recent archive so you can tail yesterday's file without gunzip.

Binary logs on MySQL 8.4 replication hosts can grow into tens of gigabytes if uncapped — a hidden cause of full disks more common than Apache logs alone. Set expire_logs_days = 7 and max_binlog_size = 100M in my.cnf or via SET GLOBAL. Verify with SHOW BINARY LOGS and purge old entries using PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 7 DAY). Binlog retention and automated database backups must be planned together; purging logs you have not backed up destroys point-in-time recovery options.

After every config change, run sudo logrotate -d /etc/logrotate.d/your-snippet for a dry-run with verbose output showing which files would rotate and which scripts would execute. Then run sudo logrotate -f /etc/logrotate.d/your-snippet to force an immediate rotation and confirm the service reloads correctly. Also audit rotation coverage after every Deployer symlink swap — a changed release path silently breaks coverage if your Laravel log snippet still points at an old directory.

Rotation configs are static but traffic is not. A simple guard script checking df /var against an eighty-five percent threshold can email a du breakdown of top /var/log consumers via cron. Alert at eighty percent with Netdata, Prometheus node_exporter, or a Nagios disk check so you have time to act before writes fail. Include PHP-FPM log paths in rotation and verify shared log paths still match snippets after Deployer deployments. Viral traffic or brute-force auth storms can produce a week's worth of logs in hours.

For single VPS hosts running Laravel booking apps or WooCommerce stores, logrotate plus journald caps handle most disk pressure locally. Multi-server fleets need shipping and central retention — the article references Loki with Grafana and Fluent Bit agents for aggregated remote logs. Rotate aggressively on each node and ship compressed archives to object storage if you need months of retention for SEO log analysis or compliance. File rotation alone does not scale across a fleet; you need both local retention policies and a central aggregation layer.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: