
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
logrotatewith sensible defaults - Per-service rules for Nginx/Apache, PHP-FPM, and mail logs
- A safe approach for “custom” app logs in
/var/logand/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:
weeklyordailyrotation based on log volumerotate 14(or 30) so retention stays predictablecompressplusdelaycompressto avoid breaking picky toolingdateextso 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
postrotatereload 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 verifygzipexists. - 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 200Mrotation 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 (
0640is a solid baseline). - Keep the
admgroup 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:
- Disk alert: page at 80–85% usage, not 95%.
- 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 +L1shows no large deleted log files held openlogrotate -dandlogrotate -frun 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.