
Your VPS doesn’t run out of disk space because “logs exist.” It fills up when log retention is undefined. On Linux in 2026, you usually have three logging layers:
- systemd-journald
- Classic text logs under
/var/log(rotated by logrotate) - A syslog pipeline (often rsyslog) writing its own files
This hands-on VPS log retention policy tutorial shows you how to set retention targets, enforce them in config, and confirm rotation, compression, and archiving behave as intended.
Examples use Ubuntu 24.04 LTS and AlmaLinux/Rocky 9/10-style layouts. The same checks apply to most VPS images.
What you’re building: a VPS-friendly retention plan
A retention plan only helps if it answers practical questions:
- How long do you keep logs locally? (e.g., 14–30 days)
- How much disk can logs consume? (e.g., 2–5% of the root filesystem)
- What gets archived off-server? (e.g., weekly compressed bundles, or continuous log shipping)
- What’s your restore/forensics need? (e.g., keep auth + web access logs longer than debug logs)
For most small-to-mid hosting VPS setups, this mix stays sane:
- Local: 14 days for most logs, 30 days for auth/security logs.
- Cap: journald capped at 512MB–2GB depending on disk size.
- Archive: weekly archive to object storage or another box (or ship continuously).
Prerequisites and quick baseline checks
Start with disk layout and current log usage. Run as root (or with sudo):
df -h /
df -h /var || true
sudo du -sh /var/log/* 2>/dev/null | sort -h | tail -n 20
sudo journalctl --disk-usage
If /var lives on its own filesystem, you get a built-in blast radius.
If it doesn’t, be stricter with caps. Logs can take the whole machine down.
Next, confirm what’s running and generating logs:
systemctl status systemd-journald --no-pager
systemctl status rsyslog --no-pager || true
nginx -v 2>&1 || true
httpd -v 2>&1 || true
mysql --version 2>&1 || true
If you need a broader baseline hardening checklist first, reference Linux VPS setup checklist in 2026.
VPS log retention policy: choose retention targets that won’t backfire
Set retention too short and you lose the evidence you needed.
Set it too long and you eventually lose the filesystem.
This sizing guide is a solid starting point:
- Root disk ≤ 40GB: target 7–14 days local retention, journald cap 256–512MB.
- Root disk 80–160GB: target 14–30 days, journald cap 1–2GB.
- Dedicated server with large disks: retention can be longer, but still cap to avoid “silent growth.”
Protect security logs first: SSH/auth, sudo, WAF/firewall, and control panel logins.
They’re usually small. You’ll miss them immediately during incident response.
Verbose application logs are the opposite. They’re easy to generate and hard to store responsibly.
Step 1 — Set hard caps for journald (system logs) on Ubuntu, Debian, AlmaLinux, and Rocky
journald can keep logs in memory, on disk, or both.
Many VPS images default to persistent storage. That’s fine if you set hard limits.
Edit:
- Ubuntu/Debian:
/etc/systemd/journald.conf - AlmaLinux/Rocky:
/etc/systemd/journald.conf
sudo nano /etc/systemd/journald.conf
Set (or uncomment) a policy that matches your disk and retention target:
[Journal]
Storage=persistent
SystemMaxUse=1G
SystemKeepFree=2G
MaxRetentionSec=14day
Compress=yes
RateLimitIntervalSec=30s
RateLimitBurst=2000
What these knobs actually do:
SystemMaxUseis the on-disk ceiling for the journal.SystemKeepFreekeeps journald from consuming your last free gigabytes.MaxRetentionSecexpresses the time goal; size limits still win when space is tight.
Restart journald and confirm the cap is in effect:
sudo systemctl restart systemd-journald
sudo journalctl --disk-usage
sudo journalctl --since "14 days ago" -n 3
If usage keeps growing past your settings, check for an overriding drop-in under /etc/systemd/journald.conf.d/*.conf:
sudo ls -la /etc/systemd/journald.conf.d/ 2>/dev/null || true
sudo systemd-analyze cat-config systemd/journald.conf | sed -n '1,120p'
Step 2 — Make logrotate enforce time + size goals (not just “weekly”)
Most distros already run logrotate daily via cron or a systemd timer.
The usual problem is the policy. Defaults may keep too many rotations, rotate too slowly, or miss your highest-churn logs.
Start by checking how logrotate runs on this machine:
systemctl list-timers | grep -E 'logrotate|cron' || true
sudo cat /etc/cron.daily/logrotate 2>/dev/null || true
sudo systemctl status logrotate --no-pager 2>/dev/null || true
Then look at the global defaults:
sudo sed -n '1,200p' /etc/logrotate.conf
A reasonable baseline for a hosting VPS looks like this:
# /etc/logrotate.conf
weekly
rotate 8
create
compress
delaycompress
dateext
su root adm
include /etc/logrotate.d
This keeps roughly eight weeks if rotation is weekly.
For web servers, weekly is often too slow.
Instead of switching everything to daily globally, keep the global file conservative.
Tune the noisy services in /etc/logrotate.d/.
Dry-run the current configuration (no changes made):
sudo logrotate -d /etc/logrotate.conf | less
Then do a one-time forced rotation during a maintenance window:
sudo logrotate -f /etc/logrotate.conf
One failure mode to watch for: the service keeps writing to the old file after rotation.
Good stanzas trigger a reload, or use copytruncate when reload isn’t available.
Step 3 — Tune web server logs (Nginx/Apache) for predictable growth
Access logs tend to dominate disk usage.
On WordPress or WooCommerce, crawler traffic alone can make access logs your largest “application” by storage.
Nginx typically logs to /var/log/nginx/access.log and /var/log/nginx/error.log. Check its current logrotate rules:
sudo cat /etc/logrotate.d/nginx 2>/dev/null || true
A practical Nginx stanza for busy sites:
/var/log/nginx/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
[ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
Force a rotation and confirm Nginx reopens fresh files cleanly:
sudo logrotate -f /etc/logrotate.d/nginx
sudo ls -lh /var/log/nginx/
sudo nginx -t
Apache (httpd) typically rotates via logrotate as well.
Inspect whichever file exists on your distro:
sudo cat /etc/logrotate.d/apache2 2>/dev/null || true
sudo cat /etc/logrotate.d/httpd 2>/dev/null || true
If you run a reverse proxy or want tighter headers/hardening while you’re here, see Nginx security hardening for a production-safe checklist.
Step 4 — Keep MySQL/MariaDB logs useful without hoarding them
Database logs are a balancing act.
You want enough history to spot patterns, but not an endless archive of noise.
For MySQL 8.x / MariaDB 10.x on Linux, you may see:
- Error log (essential)
- Slow query log (enable intentionally)
- General log (usually disabled on production)
If you plan to use the slow query log for performance work, enable it intentionally and rotate it daily.
HostMyCode has a focused walkthrough here: enable and analyze the MySQL slow query log.
Find where your MySQL error log is configured:
sudo grep -R "log_error" -n /etc/mysql /etc/my.cnf /etc/my.cnf.d 2>/dev/null | head
sudo ls -la /var/log/mysql/ 2>/dev/null || true
If you don’t already have a dedicated logrotate stanza (path varies by distro), add one:
sudo nano /etc/logrotate.d/mysql-server
/var/log/mysql/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
# Ask MySQL to reopen logs (safe for many setups)
test -x /usr/bin/mysqladmin && /usr/bin/mysqladmin flush-logs || true
endscript
}
Verify rotation and compression:
sudo logrotate -f /etc/logrotate.d/mysql-server
sudo ls -lh /var/log/mysql/
Pitfall: mysqladmin flush-logs requires credentials on some installs.
If it fails, you may see odd behavior in /var/lib/logrotate/status and in syslog.
Fix it by using a MySQL option file for root (for example, /root/.my.cnf) with strict permissions.
Or rotate only logs that don’t require a flush.
Step 5 — Use rsyslog for clean separation (and optional archiving)
On many VPS images, rsyslog is installed. It writes traditional files like /var/log/auth.log.
journald often collects the same events too. That overlap is normal.
Just account for it in your limits.
Check whether rsyslog is active and which version you’re on:
sudo systemctl status rsyslog --no-pager || true
sudo rsyslogd -v 2>/dev/null | head -n 1 || true
If you prefer simpler local log management, keep rsyslog only for the files you actually use.
Common picks are auth, mail, and specific app logs. Let journald’s caps handle the rest.
If you need a central archive (multi-VPS fleets, reseller environments, or compliance), ship logs off the VPS.
Don’t keep months locally. HostMyCode’s guide covers a solid setup: centralize logs with rsyslog.
Step 6 — Add an “archive lane” without turning it into a backup project
Retention is the short-term lifecycle.
Archiving is your long-term store.
Keep archiving boring and repeatable.
Create a weekly compressed bundle of the logs you will actually use, then move it off the VPS.
Example: archive auth + web logs once per week into /var/archives/logs, then sync to remote storage (SFTP, rsync target, or an object storage gateway).
sudo install -d -m 0750 /var/archives/logs
Create an archive script:
sudo nano /usr/local/sbin/archive-logs-weekly.sh
#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date -u +%F)
OUT="/var/archives/logs/logs-${STAMP}.tar.gz"
# Adjust paths for your stack
tar -czf "$OUT" \
/var/log/auth.log* \
/var/log/nginx/access.log* /var/log/nginx/error.log* \
/var/log/apache2/access.log* /var/log/apache2/error.log* \
2>/dev/null || true
chmod 0640 "$OUT"
# Keep only the last 8 archives locally
ls -1t /var/archives/logs/logs-*.tar.gz 2>/dev/null | tail -n +9 | xargs -r rm -f
sudo chmod +x /usr/local/sbin/archive-logs-weekly.sh
sudo /usr/local/sbin/archive-logs-weekly.sh
sudo ls -lh /var/archives/logs/
Schedule it with a systemd timer (usually cleaner than cron on modern distros):
sudo nano /etc/systemd/system/archive-logs-weekly.service
[Unit]
Description=Weekly log archive
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/archive-logs-weekly.sh
sudo nano /etc/systemd/system/archive-logs-weekly.timer
[Unit]
Description=Run weekly log archive
[Timer]
OnCalendar=Sun *-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now archive-logs-weekly.timer
systemctl list-timers | grep archive-logs
If you want log archives to be part of a real restore plan (you should), align them with your server backups.
For a restore-first approach, see Linux VPS disaster recovery plan.
Step 7 — Verify rotation really works (and catch the quiet failures)
Rotation failures don’t always throw obvious errors.
You usually find them when the disk hits 100%.
Check logrotate status and recent runs:
sudo tail -n 50 /var/lib/logrotate/status 2>/dev/null || true
sudo journalctl -u logrotate --since "7 days ago" --no-pager 2>/dev/null || true
Confirm compression is happening:
sudo find /var/log -maxdepth 2 -type f -name "*.gz" | head
Hunt for logs that never rotate.
Common examples include custom app logs under /var/www, Node/Python processes, and control panel plugins:
sudo find /var -type f -size +200M -name "*.log" 2>/dev/null | head -n 30
sudo lsof | grep deleted | head -n 30 || true
deleted files held open by a process won’t release disk until that process reloads or restarts.
This is the classic “I rotated the logs but nothing changed” situation.
Step 8 — Add guardrails: alerts before disk hits 95%
Retention prevents the slow creep.
Monitoring catches the weird stuff. That includes runaway apps, stuck processes, or a missed logrotate stanza.
For a single VPS, Netdata is a lightweight option that gets you disk alerts quickly.
Install and secure it, then set thresholds. HostMyCode’s walkthrough is practical: Linux VPS monitoring with Netdata.
Even without a full monitoring stack, put something in place.
A daily cron/systemd check that emails you at 80–85% usage beats finding out during an outage.
If you already run Prometheus/OpenTelemetry, ship filesystem metrics to your central alerting.
Keep alerts tight: disk usage, inode usage, and growth rate usually cover it.
Common pitfalls (and how to avoid them)
- Relying on “weekly rotate” for high-traffic access logs: use daily rotation for Nginx/Apache on busy sites.
- Unlimited journald growth: always set
SystemMaxUseandSystemKeepFree. - Rotating without reload: ensure services reopen logs after rotation (Nginx uses
USR1). - Ignoring application logs outside /var/log: add stanzas for
/var/www/*/logsor wherever your app writes. - No restore story: archives are only valuable if you can find and read them quickly.
If you’re cleaning up a server that’s already bloated, pair this with VPS disk space cleanup: stop “No space left on device” outages.
Where HostMyCode fits (VPS vs managed VPS vs dedicated)
If you run multiple sites, mail, and a database on one box, log retention becomes a stability feature.
A small VPS can handle it. You need limits and follow-up checks.
For predictable performance and full root control, start with a HostMyCode VPS.
If you’d rather hand off baseline hardening, updates, and day-2 operations like log retention and alerting, managed VPS hosting is the better fit.
If your logs are growing faster than you can review them, your VPS is doing real work—and it needs clearer guardrails. HostMyCode can provision a right-sized VPS or handle the routine reliability tasks on managed VPS hosting, so “disk full” doesn’t turn into a recurring incident.
FAQ
Should I keep both journald and rsyslog file logs?
Yes. For many hosting setups, that’s normal.
Cap journald for safety, and keep a few key text logs (auth, web) for fast, grep-friendly investigation.
What’s a safe default for journald size on a VPS?
On a typical 80–160GB VPS, 1GB is a reasonable cap.
On smaller disks, start at 256–512MB and increase only if your troubleshooting needs justify it.
My disk space didn’t drop after rotation. Why?
A process may still be holding an old log file open after it was rotated and deleted.
Check lsof | grep deleted, then reload or restart the service.
How long should I keep Nginx access logs?
For most sites, 14 days locally is enough.
If you need longer history for fraud analysis or SEO investigations, archive weekly bundles off-server instead of keeping months on the VPS.
Summary: a retention policy you can defend at 3am
A working VPS log retention policy has explicit caps, service-specific rotation where volume is highest, and a straightforward archive lane for the logs you’ll actually use.
Cap journald, rotate noisy logs daily, compress what you keep, and verify with forced rotations and open-file checks.
If you’re outgrowing a single machine—or you just want fewer surprises—move to a larger plan or step up to dedicated servers once traffic and log volume justify it.
The mechanics stay the same: define retention, enforce it, and monitor the result.