
A “disk full” incident on a hosting server almost never comes from one massive file. It’s usually slow creep. Logs don’t rotate, backups get forgotten, cache directories grow forever, and container images hang around for months. This VPS cleanup tutorial shows how to find the real space hogs, reclaim disk safely, and add limits so you’re not back here next week.
The commands below target Ubuntu 24.04/26.04 LTS and Debian 12/13. They also translate cleanly to AlmaLinux/Rocky, with a few path tweaks.
If the server is already near 100% usage, use a maintenance window. MySQL writes, mail queues, and PHP session writes can fail once free space hits zero.
Before you delete anything: take a quick safety snapshot
On production systems, the best rollback is a snapshot or fast restore point. If this VPS runs paying sites, treat that as a requirement.
- If you manage your own stack, start from a clean VPS plan like HostMyCode VPS so you can expand storage when growth is real (not just accumulated junk).
- If you don’t want to manage storage, log rotation, and backup retention yourself, use managed VPS hosting and fold cleanup into routine maintenance.
For a practical backup pattern (snapshots + offsite copy + restore checks), see this VPS backup setup guide.
Even if you already back up, the steps below help stop backups from becoming the thing that fills your disk.
Step 1: confirm what’s full (filesystem, inode, or both)
Start with these three checks. They tell you if you’re out of bytes, out of inodes, or dealing with a mount/layout issue.
df -hT
df -ih
lsblk -f
- df -hT shows which filesystem is full and the type (ext4, xfs, etc.).
- df -ih reveals inode exhaustion. This is common with millions of small files (sessions, cache keys, maildir spam).
- lsblk -f confirms what’s mounted where. Don’t “clean root” if
/varis a separate filesystem.
If inodes are the problem, stop hunting for “big files.” Reduce file counts instead (see Step 4).
Step 2: find the top space users fast (without guessing)
Use two passes. First, find the biggest directories. Then drill into the top offenders.
2A) High-level directory scan
sudo du -xhd1 / 2>/dev/null | sort -h
Notes:
- -x stays on the same filesystem. That keeps totals honest when you have multiple mounts.
- If
/varis separate, run the same command on/varand/home.
2B) Deep scan of the usual suspects
sudo du -xhd1 /var 2>/dev/null | sort -h
sudo du -xhd1 /home 2>/dev/null | sort -h
sudo du -xhd1 /opt 2>/dev/null | sort -h
2C) Find very large files (quick win list)
sudo find / -xdev -type f -size +1G -printf '%s %p\n' 2>/dev/null | sort -n | tail -50
On hosting VPSs, the top offenders usually land in one of these buckets:
/var/loggrowing without rotation/var/lib/mysql(database growth, binary logs)/var/mailor/var/vmail(mailboxes, queue)/home/*(old site backups, uploads)/var/lib/docker(images, layers, build cache)
If the disk event came with timeouts and 5xx errors, free space first. Then run a quick performance check using this slow VPS troubleshooting tutorial.
Step 3: reclaim space from logs (safely, and with retention)
Logs are the most common “silent growth” source on web servers.
Avoid blind deletes. Set rotation, enable compression, and keep a sane amount of history.
3A) Check journald size (systemd logs)
journalctl --disk-usage
If it’s large, cap it. Create or edit /etc/systemd/journald.conf:
sudo nano /etc/systemd/journald.conf
[Journal]
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=14day
sudo systemctl restart systemd-journald
To reclaim space immediately (choose one):
sudo journalctl --vacuum-size=500M
# or
sudo journalctl --vacuum-time=14d
3B) Identify the biggest classic log files
sudo du -sh /var/log/* 2>/dev/null | sort -h | tail -30
Common culprits:
/var/log/nginx/access.loganderror.log/var/log/apache2/access.loganderror.log/var/log/mail.log,/var/log/maillog,/var/log/mail.err/var/log/mysql/error.logor/var/log/mariadb/mariadb.log
3C) Don’t delete active logs—truncate them correctly
If a log is tens of GB and you need relief now, truncate it. This keeps ownership, permissions, and the active file handle intact:
sudo truncate -s 0 /var/log/nginx/access.log
sudo truncate -s 0 /var/log/nginx/error.log
If log rotation is configured properly, you shouldn’t need truncation often.
Check what logrotate thinks it will do:
sudo logrotate -d /etc/logrotate.conf | head -200
Then force a run (safe; it won’t break the file handle):
sudo logrotate -f /etc/logrotate.conf
3D) Fix missing rotation for a custom app
If a custom app writes to /var/log/myapp.log, add a logrotate rule. This prevents unlimited growth.
sudo nano /etc/logrotate.d/myapp
/var/log/myapp.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
If you need clearer “what changed?” visibility over time, tighten up log habits. See this VPS log auditing tutorial.
Step 4: fix inode exhaustion (millions of small files)
If df -ih shows 90–100% inode usage, you have file-count bloat.
The fastest path is to find directories that generate huge numbers of small files.
4A) Find directories with huge file counts
sudo find /var -xdev -type d -printf '%p\n' 2>/dev/null | while read -r d; do
c=$(sudo find "$d" -maxdepth 1 -type f 2>/dev/null | wc -l)
if [ "$c" -gt 5000 ]; then echo "$c $d"; fi
done | sort -n | tail -30
Hosting-related hotspots:
- PHP sessions:
/var/lib/php/sessions - WordPress cache: plugin cache directories under
wp-content/cache - Maildir: spam storms can explode file counts under
/home/*/mailor/var/vmail - Temp uploads:
/tmpor app-specific temp paths
4B) Clean PHP sessions safely
On Ubuntu/Debian, cron usually purges PHP sessions. That policy can drift over time.
First check how big the sessions directory is:
sudo du -sh /var/lib/php/sessions 2>/dev/null
Then delete sessions older than 7 days (adjust to your environment):
sudo find /var/lib/php/sessions -type f -mtime +7 -delete
If you host WordPress and scheduled tasks aren’t firing, stale sessions and cache often pile up.
Fix the root cause with WordPress cron troubleshooting so cleanups run on schedule.
Step 5: remove old backups and build proper retention (the right way)
Backups should save you. On a tight disk, they can also take the server down.
The fix is retention plus offsite storage. Don’t “keep everything forever in /home.”
5A) Locate backup dumps and archives
sudo find /home /var/backups -type f \( -name '*.tar' -o -name '*.tar.gz' -o -name '*.zip' -o -name '*.sql' -o -name '*.sql.gz' \) -printf '%TY-%Tm-%Td %s %p\n' 2>/dev/null | sort | tail -50
5B) Apply a retention rule (example: keep 14 days)
Example for a backup directory /var/backups/sites:
sudo find /var/backups/sites -type f -mtime +14 -delete
If you run a control panel, use its retention settings instead of manual cleanup:
- DirectAdmin users: set automated backups with retention and restore verification using this DirectAdmin backup configuration tutorial.
- cPanel users: configure backup destinations (SFTP/S3) and prune local copies. Don’t let
/backupconsume your root volume.
5C) Offload backups off the VPS
Local backups aren’t offsite backups. For production, keep at least one copy off the server.
Test restores monthly. A solid baseline is snapshots + offsite archive + a simple restore drill.
Step 6: clean package cache and old kernels (Ubuntu/Debian)
Package cache usually won’t consume 100 GB. On small volumes, it still adds up.
Old kernels can pile up too. This is common on systems that auto-update for months.
sudo apt update
sudo apt -y autoremove --purge
sudo apt -y autoclean
sudo apt -y clean
Check what’s still installed:
dpkg -l | grep -E 'linux-image|linux-headers' | awk '{print $2}'
On Ubuntu, autoremove usually handles kernel cleanup correctly.
Don’t purge the kernel you’re currently running:
uname -r
Step 7: clean web stack caches (Nginx, Apache, PHP, WordPress) without breaking pages
“Clear cache” can mean different things. It might be a server proxy cache, an app/plugin cache, or user sessions.
Handle each cache separately. This helps you avoid deleting data you still need.
7A) Nginx FastCGI cache (if you use it)
If you configured fastcgi_cache_path, locate the cache directory:
sudo nginx -T 2>/dev/null | grep -R "fastcgi_cache_path" -n || true
A common location is /var/cache/nginx. Check its size:
sudo du -sh /var/cache/nginx 2>/dev/null
Safe cleanup: delete cache files (not the directory), then reload Nginx:
sudo find /var/cache/nginx -type f -delete
sudo nginx -t && sudo systemctl reload nginx
If you want caching that stays bounded and easy to purge, add limits to your cache config. The setup is covered in this Nginx caching configuration tutorial.
7B) WordPress cache directories
Plugin caches often live under:
wp-content/cache/wp-content/uploads/cache/- Plugin-specific folders (varies by plugin)
Clear cache inside the plugin UI first. That gives the plugin a clean rebuild path.
If you must do it on disk, double-check the paths. Delete only cache directories, not uploads.
cd /var/www/example.com/public_html
sudo du -sh wp-content/cache 2>/dev/null
sudo rm -rf wp-content/cache/*
Step 8: Docker and container bloat (if your VPS runs containers)
On developer VPSs, /var/lib/docker can quietly become the largest directory on the system.
Start by checking what Docker thinks it’s using:
docker system df
Then prune:
# Remove stopped containers, unused networks, dangling images, build cache
docker system prune -f
# If you want to remove unused images (not used by any container)
docker image prune -a -f
Pruning removes images you’ll need to pull again. That’s usually fine.
It can slow deployments if your registry or network is sluggish.
Step 9: mail queue, mail logs, and mailbox growth
Mail fills disks in two common ways. You might have a stuck queue with thousands of deferred messages. Or you might have mailbox growth with no quotas.
If you host email on the same VPS, check both.
9A) Check queue size (Postfix)
sudo postqueue -p | tail -n 20
sudo mailq | grep -i "requests"
If the queue is huge, don’t just delete it. Find out why it’s stuck.
Common causes include DNS, rDNS, SPF/DKIM, remote rejections, and rate limits. Use this email queue troubleshooting tutorial and this deliverability troubleshooting guide to prevent repeat pileups.
9B) Locate mailbox storage
Typical paths:
/var/vmail(virtual mailboxes)/home/*/mailor/home/*/Maildir(local mail)
sudo du -sh /var/vmail 2>/dev/null
sudo du -sh /home/*/mail 2>/dev/null | sort -h | tail -20
Set mailbox quotas and basic archive rules if you host email for multiple users.
If you’re a reseller, quotas help keep storage predictable.
Step 10: verify what you freed, then add guardrails
After cleanup, confirm the numbers. Then verify services are healthy.
df -hT
sudo systemctl --failed
sudo tail -n 50 /var/log/syslog 2>/dev/null || true
sudo tail -n 50 /var/log/messages 2>/dev/null || true
10A) Add a simple disk alert (fast and practical)
Full monitoring is better. A simple cron job still beats learning about low disk space from customer reports.
Create /usr/local/sbin/disk-alert.sh:
sudo nano /usr/local/sbin/disk-alert.sh
#!/bin/sh
THRESH=85
df -P -h | awk 'NR>1 {print $5 " " $6}' | while read -r use mount; do
pct=$(echo "$use" | tr -d '%')
if [ "$pct" -ge "$THRESH" ]; then
logger -t disk-alert "Disk usage ${pct}% on ${mount}"
fi
done
sudo chmod +x /usr/local/sbin/disk-alert.sh
Schedule it:
sudo crontab -e
*/15 * * * * /usr/local/sbin/disk-alert.sh
If you want a proper dashboard with alerts (CPU, RAM, disk, IO, services), set up Netdata using this monitoring setup guide.
Cleanup checklist (printable)
- Confirm
df -handdf -ih(bytes vs inodes). - Run
du -xhd1on/,/var,/home. - Vacuum journald and cap retention in
/etc/systemd/journald.conf. - Fix logrotate and compress logs; truncate only in emergencies.
- Apply backup retention; move backups off-host.
- Clean apt caches; autoremove old packages/kernels.
- Clear bounded caches (Nginx FastCGI cache, WordPress plugin caches) carefully.
- Prune Docker artifacts if applicable.
- Check mail queue and mailbox growth if email is hosted locally.
- Add disk alerts so the server tells you early.
Summary: keep the VPS clean without playing whack-a-mole
Disk bloat becomes predictable once you know your repeat offenders. The long-term fix is rotation, retention, and alerting.
Avoid panic deletes. If uptime matters, treat disk like any other monitored resource.
If you want a platform that’s easy to scale and straightforward to manage, start with HostMyCode VPS. If you’d rather hand off cleanup, patching, and operational hygiene, use managed VPS hosting from HostMyCode.
If you keep hitting disk alerts, you usually don’t have a “mystery problem”—you have missing retention limits or storage that doesn’t match the workload. HostMyCode can help you stabilize usage on a HostMyCode VPS, or you can hand off day-to-day maintenance with managed VPS hosting and stay focused on running your sites.
FAQ
Is it safe to delete files in /var/log?
It’s safer to rotate and compress logs with logrotate. If you need emergency space, use truncate -s 0 on the log file so the service keeps its file handle.
Why does df show space used even after I deleted big files?
A process may still have the deleted file open. Find it with sudo lsof | grep '(deleted)', then restart the owning service or process.
How do I prevent backups from filling my VPS again?
Keep short retention locally (7–14 days), push at least one copy offsite, and run restore tests. Control panels usually have retention settings—use them.
What’s the fastest way to find a sudden disk spike?
Run du -xhd1 /var and find / -xdev -type f -size +1G. On most hosting servers, the answer is logs, backups, or mail queue growth.
Should I upgrade storage or keep cleaning?
If legitimate data growth (uploads, mailboxes, databases) is the cause, upgrade storage. If it’s garbage growth (logs, cache, old backups), fix retention first, then size capacity based on real usage.