Back to tutorials
Tutorial

VPS Log Rotation Tutorial (2026): Fix Giant Logs, Keep 14-Day Retention, and Stop /var From Filling Up

VPS log rotation tutorial (2026): configure logrotate, compress safely, set retention, and verify services keep logging after rotate.

By Anurag Singh
Updated on Oct 02, 2026
Category: Tutorial
Share article
VPS Log Rotation Tutorial (2026): Fix Giant Logs, Keep 14-Day Retention, and Stop /var From Filling Up

Your VPS rarely runs out of disk space because of “mystery files.” It usually happens because logs grow quietly, rotation is misconfigured, or a daemon keeps writing to an old file handle after rotation. This VPS log rotation tutorial shows how to fix that on Ubuntu/Debian and AlmaLinux/Rocky, so /var stops creeping toward 100%.

The goal is simple: predictable retention (for example, 14 days), compression that won’t trip up daemons, and clear proof that services keep logging after rotation.

You’ll also add a couple of alerts, so you catch log explosions before users do.

What you’ll build (and what to collect before you start)

By the end, you’ll have:

  • Working logrotate with sensible defaults
  • Per-service rules for Nginx/Apache, PHP-FPM, and mail logs
  • A safe approach for “custom” app logs in /var/log and /home/*
  • Verification steps: file handles, post-rotate reloads, and dry runs

Before you touch anything, capture a baseline.

You want to know what is actually using disk.

# Disk and log sizes
sudo df -h / /var
sudo du -sh /var/log/* 2>/dev/null | sort -h | tail -n 20

# Biggest individual log files
sudo find /var/log -type f -size +200M -print0 | sudo xargs -0 ls -lh 2>/dev/null | sort -k5 -h

If the VPS hosts customer sites, schedule this work for a low-traffic window. Rotation is usually safe.

The real risk is a bad rule that reloads or restarts something at the wrong time.

If you need a reliable place to run multi-site workloads with predictable I/O, start with a HostMyCode VPS. Rotation won’t replace capacity planning.

It does stop the slow leak that makes even big disks feel tiny.

Install and sanity-check logrotate (Ubuntu/Debian + AlmaLinux/Rocky)

Most distros install logrotate by default. Still, confirm it exists.

Then verify something runs it on schedule.

# Ubuntu/Debian
dpkg -l | grep -E '^ii\s+logrotate\b' || sudo apt update && sudo apt -y install logrotate

# AlmaLinux/Rocky
rpm -q logrotate || sudo dnf -y install logrotate

Check the scheduler:

# systemd timer (common on modern distros)
systemctl list-timers | grep -i logrotate || true

# cron fallback
test -f /etc/cron.daily/logrotate && echo "cron.daily present"

Now open the global config:

sudo nano /etc/logrotate.conf

For a hosting VPS in 2026, these defaults usually work well:

  • weekly or daily rotation based on log volume
  • rotate 14 (or 30) so retention stays predictable
  • compress plus delaycompress to avoid breaking picky tooling
  • dateext so rotated names are stable and easy to restore

For most hosting stacks, daily rotation with 14–30 days retention is the sweet spot.

Weekly rotation often creates multi-GB files. Those are painful to search and slow to ship off-box.

VPS log rotation tutorial: set a safe global baseline

Don’t fight every package stanza by hand.

Put guardrails in /etc/logrotate.conf. Then override behavior per service in /etc/logrotate.d/ when needed.

Example baseline (tune to match your policy):

# /etc/logrotate.conf (example baseline)
daily
rotate 14
missingok
notifempty
compress
delaycompress
dateext
dateformat -%Y%m%d

# keep permissions sensible for newly created logs
create 0640 root adm

# include per-package rules
include /etc/logrotate.d

Why delaycompress? Some services and log shippers expect the newest rotated file to stay plain text for a bit.

Delaying compression by one cycle avoids those sharp edges.

Rotate web logs (Nginx or Apache) without breaking real IPs or vhosts

Web logs are often the biggest disk hogs.

Rotation only works when the web server reopens its log files.

Nginx

Many distros ship a decent rule at /etc/logrotate.d/nginx. Still, read it.

This file gets “quick fixed” a lot. Small edits can break rotation.

sudo nano /etc/logrotate.d/nginx

A solid rule looks like this:

/var/log/nginx/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        test -s /run/nginx.pid && kill -USR1 `cat /run/nginx.pid`
    endscript
}

kill -USR1 tells Nginx to reopen log files. If you skip it, Nginx can keep writing to the old inode.

When that happens, your “rotated” logs don’t free space.

If you proxy multiple sites through Nginx, keep request logging consistent across vhosts.

For a refresher on headers and real client IP logging, see Nginx front-end reverse proxy setup.

Apache (Debian/Ubuntu paths vs RHEL-family paths)

Apache log paths differ by distro:

  • Debian/Ubuntu: /var/log/apache2/*.log
  • AlmaLinux/Rocky: /var/log/httpd/*log

Example for Debian/Ubuntu:

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

Example for AlmaLinux/Rocky:

/var/log/httpd/*log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        systemctl reload httpd >/dev/null 2>&1 || true
    endscript
}

Rotate PHP-FPM logs and avoid “log spam” hiding real errors

PHP-FPM logs often live in one of these places:

  • /var/log/php*-fpm.log (Ubuntu/Debian)
  • /var/log/php-fpm/* or /var/log/php-fpm/error.log (RHEL-family)

Start by checking what’s on your box:

sudo ls -lah /var/log | grep -i fpm || true
sudo find /var/log -maxdepth 2 -type f -iname '*fpm*' -print

If you don’t already have a rule, add one.

Example for Ubuntu with PHP 8.3/8.4 packages (names vary by repo):

sudo nano /etc/logrotate.d/php-fpm-custom
/var/log/php*-fpm.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        systemctl reload php8.3-fpm 2>/dev/null || true
        systemctl reload php8.4-fpm 2>/dev/null || true
    endscript
}

If you run per-site pools (common with WordPress), logging and tuning are tied together.

One noisy plugin can drown real errors and fill the disk quickly.

For performance triage, keep this nearby: VPS performance troubleshooting.

Rotate mail logs carefully (Postfix/Exim) and keep deliverability evidence

Mail logs are operational signals and your paper trail when someone disputes a send. Rotate them.

Just don’t trim them so hard that you lose useful history.

Common locations:

  • /var/log/mail.log, /var/log/mail.err (Debian/Ubuntu)
  • /var/log/maillog (AlmaLinux/Rocky)

Example rule (Debian/Ubuntu):

/var/log/mail.log
/var/log/mail.err {
    daily
    rotate 30
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        systemctl reload rsyslog >/dev/null 2>&1 || true
    endscript
}

That’s 30-day retention on purpose.

For spam complaints, queue problems, and slow-burning deliverability issues, 14 days disappears fast.

If email is part of your hosting stack, your logs should support quick tracing.

Pair this with email log troubleshooting so you know what to pull when customers report missing mail.

Handle “custom” app logs (Node/Python apps, cron output, and vendor scripts)

The nastiest disk surprises usually aren’t OS-managed logs.

They’re app logs under /home.

They can also be cron output redirected to a file, or a vendor script that appends to /var/log/app.log forever.

Step 1: find large non-standard logs.

# Big logs anywhere under /home and /var/log
sudo find /home /var/log -type f -name '*.log' -size +200M -printf '%s %p\n' 2>/dev/null | sort -n | tail -n 30

Step 2: put custom rules in their own file.

This makes them easy to audit later.

sudo nano /etc/logrotate.d/custom-apps

Example for a typical app log directory:

/var/log/myapp/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    copytruncate
}

Use copytruncate only when you have no better option.

It copies the current log to a rotated file, then truncates the original in place.

That helps when the process can’t reopen its logs. On busy systems, it can drop a few lines during rotation.

If you control the service, prefer signaling it to reopen logs instead.

A common mistake with systemd is StandardOutput=append:/var/log/myapp/app.log without any reopen strategy.

It works—until you try to rotate. Safer choices are journald/syslog or an app logger that supports reopen signals.

Prevent “rotated but still full” disks: check open file handles

A classic failure mode looks like this: the log rotates, the old file is removed, but the daemon still holds it open.

df stays ugly until you restart the process.

Find deleted-but-open files:

sudo lsof +L1 | grep -E '/var/log|/home' | head -n 50

Large entries marked (deleted) are the giveaway. Fixes are usually straightforward:

  • Add the right postrotate reload signal in the logrotate rule, or
  • Restart the service during maintenance if it can’t reload cleanly

After you update rules, run lsof +L1 again.

Confirm the daemon releases old inodes after rotation.

Run a safe dry-run, then force a rotation (without guessing)

Use these two modes every time you change rules.

They prevent “looks fine” mistakes.

  • Debug dry-run: shows what would happen
  • Forced run: rotates now so you can validate reloads and permissions
# Dry-run (no changes)
sudo logrotate -d /etc/logrotate.conf

# Force a run (makes changes)
sudo logrotate -f /etc/logrotate.conf

Immediately after the forced run, confirm two things.

First, new files exist and have sane permissions. Second, the service keeps writing.

# New logs created and writable
sudo ls -lah /var/log/nginx 2>/dev/null | head
sudo ls -lah /var/log/apache2 2>/dev/null | head

# Services still writing
sudo tail -n 20 /var/log/nginx/access.log 2>/dev/null || true
sudo tail -n 20 /var/log/apache2/access.log 2>/dev/null || true

If logging stops after rotation, it’s usually ownership or permissions.

Add a create directive in that specific stanza instead of relying on the global default.

Retention that matches hosting reality: a practical checklist

Retention comes down to storage math and how far back you need to investigate incidents.

  • Web access/error logs: daily rotation with 14 days retention works well for many small-to-mid nodes.
  • Mail logs: 30 days helps with deliverability disputes and long-running abuse investigations.
  • Auth logs: keep at least 30 days on public-facing servers if storage allows.
  • Compress rotated logs: do it. Plain text compresses extremely well.
  • Don’t keep everything forever: if you need long retention, ship key logs off-box.

If you’re trying to run a tighter ops loop, add daily summaries so new spikes stand out.

Logwatch daily reports fit nicely alongside stable rotation rules.

Common gotchas (and quick fixes)

  • Rotation runs, but files never compress: look for a stanza that sets nocompress. Also verify gzip exists.
  • Permissions break after rotate: add create 0640 root adm (or the correct user/group) inside that stanza.
  • Custom logs under /home don’t rotate: confirm the path matches exactly. Also make sure logrotate can traverse the directory (mount options and permissions can block it).
  • Huge single-day logs: use size 200M rotation for that file instead of relying only on daily.

Example size-based rotation for a chatty access log:

/var/log/nginx/access.log {
    size 200M
    rotate 20
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        test -s /run/nginx.pid && kill -USR1 `cat /run/nginx.pid`
    endscript
}

Hardening note: logs can leak sensitive data

Rotation helps disk pressure. It does not fix privacy problems.

If apps log full URLs with tokens, or mail logs include sensitive addresses, lock things down:

  • Make sure logs aren’t world-readable (0640 is a solid baseline).
  • Keep the adm group tight.
  • Fix app logging: don’t write passwords, tokens, or full POST bodies to disk.

On multi-customer VPS setups, isolation and conservative defaults matter.

If you run cPanel-style environments, account-level containment often matters more than people expect.

Operational add-on: monitor log growth so rotation isn’t your only line of defense

Rotation can fail quietly. This is common after a config change or package update.

A small amount of monitoring catches that early.

Two lightweight checks cover most incidents:

  1. Disk alert: page at 80–85% usage, not 95%.
  2. Log size alert: notify if a single file crosses a threshold (example: 1–2 GB).

Example daily check (cron) that emails root if any log exceeds 2 GB:

sudo nano /etc/cron.daily/logsize-alert
#!/bin/sh
THRESHOLD=$((2*1024*1024*1024))
FOUND=$(find /var/log -type f -size +2048M -printf '%s %p\n' 2>/dev/null | sort -n | tail -n 20)

if [ -n "$FOUND" ]; then
  echo "Large log files detected (over 2GB):\n\n$FOUND" | mail -s "[ALERT] Large logs on $(hostname)" root
fi
sudo chmod +x /etc/cron.daily/logsize-alert

If you prefer dashboards and paging, run a small monitoring stack alongside this.

HostMyCode customers commonly pair resource alerts with log hygiene, especially on reseller nodes where one tenant can create surprise load.

Summary: the “done” checklist you can keep

  • Global baseline in /etc/logrotate.conf: daily + rotate 14 + compress + dateext
  • Verified web log rules reload Nginx/Apache properly
  • PHP-FPM logs rotate and pools keep writing after rotation
  • Mail logs rotate with longer retention (often 30 days)
  • lsof +L1 shows no large deleted log files held open
  • logrotate -d and logrotate -f run clean
  • Alerts exist for disk usage and abnormal log growth

If you want predictable performance as you scale, treat log rotation as part of the baseline build.

A managed VPS hosting plan from HostMyCode can give you a clean starting point to standardize logging, backups, and monitoring across multiple projects.

Need a VPS that stays stable under real hosting workloads? HostMyCode offers VPS hosting and managed VPS hosting for multi-site stacks where log growth and disk pressure are constant chores.

If you’re migrating from shared hosting or consolidating several sites, you get the control to standardize rotation, backups, and maintenance windows without fighting the platform.

FAQ

Should I rotate logs daily or weekly on a VPS?

Daily is the safer default for hosting. It keeps files small, makes grepping faster, and compresses better.

Weekly only makes sense on low-traffic servers with minimal logging.

What’s the difference between “compress” and “delaycompress”?

compress gzips rotated logs. delaycompress waits one rotation cycle before compressing the most recently rotated file.

This helps avoid edge cases with tooling that expects plain text.

When should I use copytruncate?

Use it only when the process can’t be told to reopen logs.

It works, but on busy systems it can drop a small number of lines during rotation.

How do I know if a service is still writing to a deleted log file?

Run sudo lsof +L1. If you see a large file marked (deleted), the process still has the file handle open.

Add a proper postrotate reload or restart the service safely.

Can log rotation help with security investigations?

Yes—if retention is long enough and logs stay consistent and readable.

Daily summaries help you spot unusual spikes quickly. Pair rotation with reporting like Logwatch so suspicious changes don’t blend into normal noise.