A bot stops saving state. A database refuses a write. A Docker deployment fails halfway through an image pull. They can all produce a “No space left on device” error, but buying a bigger virtual disk is not always the right first response.
If this is a production incident, pause nonessential imports, builds and backup jobs that are still generating data. Keep your current administrative session open and confirm you have panel console access. Avoid an unplanned reboot: a server with no working space may fail to bring its applications back online.
1. Identify which filesystem is actually full
Run these checks over SSH or through your VPS console:
df -hT
df -i
lsblk -f
df -hT shows filesystem capacity and type; df -i shows inode usage. The Mounted on column matters as much as the percentage. A full /var is a different problem from a full /boot, even when both belong to the same VPS. See the GNU df manual.
Check the exact directory mentioned in the error. This example checks /var; substitute an existing directory where your application writes:
df -hT /var
df -i /var
findmnt -T /var
| What you find | Likely direction | Next check |
|---|---|---|
| Almost no available bytes | Files or filesystem data consume the space | Inspect directory sizes |
| Inodes at or near 100% | Too many filesystem objects | Find directories with many small files |
| df is much larger than du | Open deleted files, hidden data or filesystem accounting | Inspect open files and mounts |
| Root has room, another mount is full | The application writes somewhere else | Follow the exact failing path |
| A tmpfs mount is full | Temporary memory-backed storage is exhausted | Inspect that mount and its producer |
If the error is “Disk quota exceeded”, investigate the account or project quota too. If it is “Read-only file system”, investigate mount state and kernel errors instead of assuming ordinary capacity exhaustion. Do not force a damaged filesystem writable to make the message disappear.
2. Find large directories without crossing other filesystems
Start broad, then inspect one level deeper. These commands report usage without removing anything:
sudo du -xhd1 / 2>/dev/null
sudo du -xhd1 /var 2>/dev/null
sudo du -xhd1 /var/log 2>/dev/null
GNU du's -x stays on the starting filesystem and -d1 limits the displayed depth. Scan a separate data mount explicitly if that is the full filesystem. The error redirection hides warnings, so rerun without it if a result looks incomplete. A deep scan can still create substantial disk I/O. See the GNU du manual.
Common suspects include application uploads, database directories, old backup archives and container storage. Finding a large database directory is not permission to delete its contents: tables, transaction logs and recovery files belong to the database's own lifecycle.
Look for an explanation, not just a large number. A 40 GB media library may be expected; a log growing several gigabytes an hour is not. Compare application activity with the point when disk usage changed. Avoid installing extra diagnostic packages while the root filesystem has no room to unpack them.
3. Check for inode exhaustion and small-file growth
On filesystems with a finite inode pool, a huge number of small files can prevent new files being created even when there are free gigabytes. Cache directories, session files and abandoned job outputs are useful places to investigate.
sudo du --inodes -x -d1 /var 2>/dev/null
Follow the largest count into the relevant directory. For example, if an application's session cache is responsible, check its configured expiry and garbage collection. Use that application's supported cleanup process rather than recursively deleting a system directory.
Correct the producer as well as the backlog. Otherwise a cleanup merely resets the countdown to the next incident. Keep enough representative information to understand why the files accumulated, but do not copy millions of files to another directory on the same full filesystem. That does not create capacity.
4. Find deleted files that still occupy disk space
Removing a directory entry does not necessarily release its blocks immediately. A process may still hold the file open. If lsof is already installed, inspect files with no remaining links:
sudo lsof +L1
Check the command, PID, size and filename. Coordinate a supported log reopen, reload or restart of the owning service; the space is normally released once the final reference closes. Do not kill a database process or truncate a file descriptor just because it appears in this list. The lsof manual documents the link-count selection.
A disagreement between df and du is a clue, not proof of this cause. Filesystem metadata, reserved capacity, snapshots and files hidden underneath a mount can also affect the totals. A backup job can accidentally write into a local mountpoint when its remote filesystem is absent. Check mount state before starting the next backup; do not unmount a busy production filesystem simply to look underneath it.
5. Recover space from logs and package caches deliberately
System journal: inspect before reducing history
sudo journalctl --disk-usage
If the journal is a significant contributor, preserve any logs needed for incident investigation or retention requirements first. The following example deletes older archived journal history to work towards a 500 MB size limit; choose a policy appropriate to your service:
sudo journalctl --rotate --vacuum-size=500M
sudo journalctl --disk-usage
Vacuuming acts on archived journal files, not active ones. Rotation makes the current files eligible, but the final total is not guaranteed to equal the requested size. This is a one-time cleanup, not a permanent retention policy. Configure journald limits separately if needed. See the systemd journalctl manual.
APT cache: remove downloaded packages, not installed software
On Debian and Ubuntu, first see whether the download cache is worth clearing:
sudo du -sh /var/cache/apt/archives
If you do not need the cached installers for offline recovery, this removes downloaded package archives:
sudo apt-get clean
It does not uninstall your applications. It also cannot reclaim files that were never in that cache. Do not substitute a blanket package-removal command. The APT manual distinguishes cache cleaning from removing packages.
Application logs: use the configured rotation mechanism
For web servers, bots and custom services, identify the log destination and its rotation policy. Preserve evidence before shortening retention. A noisy error loop should be fixed at source; keeping only a tiny history can conceal a recurring fault without solving it.
6. Investigate Docker disk usage and stop runaway logs
On a Docker host, separate images, writable container layers, volumes and build cache before choosing any cleanup:
sudo docker system df -v
sudo docker ps -a --size
sudo docker info --format '{{.DockerRootDir}}'
docker system df reports Docker's object usage, not every byte consumed anywhere on the host. Bind-mounted application data and log storage need separate attention. Inspect the data root reported by your own daemon rather than assuming every installation uses the same path.
For each growing service, inspect its current logging configuration. Replace CONTAINER_NAME with the actual name:
sudo docker inspect --format '{{json .HostConfig.LogConfig}}' CONTAINER_NAME
Docker's local logging driver rotates logs and can use explicit limits. Merge this fragment into the relevant service in your existing Compose file; it is not a complete application definition:
services:
app:
# Keep your existing image, volumes, networks and other settings.
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
This bounds the retained stdout/stderr logs for that container, not logs the application writes into a bind mount or volume. Check compatibility with any log collector before changing drivers. Use application-specific retention for file-based logs too.
After confirming persistent data is stored outside the container's writable layer and you have recoverable backups, apply the change during a maintenance window. Replace app with the real Compose service name:
sudo docker compose config --quiet
sudo docker compose up -d --no-deps --force-recreate app
Recreation interrupts that service and replaces its writable layer. A simple restart does not change the container's logging configuration. Recheck the configuration and health afterwards. Do not manually delete or truncate Docker-managed log files; see the local logging driver documentation and Compose logging reference.
7. Prevent the next full disk
After each controlled change, rerun the checks against the affected filesystem and verify that the application can save data again. Do not declare the incident resolved simply because the percentage dropped. Test the failed operation, inspect service health and confirm scheduled jobs are no longer immediately filling the reclaimed space.
- Monitor every relevant mount: root, application data and backup destinations, plus inode usage where applicable.
- Alert with headroom: use both free capacity and growth rate. An example 80% warning and 90% critical threshold should be adjusted to your disk size, write rate and response time.
- Bound retention: set policies for logs, uploads, build artifacts and backups separately.
- Test missing-mount handling: a backup should fail visibly if its intended destination is unavailable.
- Keep recovery copies elsewhere: a backup on the same disk competes with production and shares its failure risks.
Our Beszel monitoring guide is a useful starting point for visibility across your servers. Pair monitoring with ownership: someone needs to receive the alert and know which cleanup procedure is safe.
8. When to add storage, and where HYEHOST fits
Once growth is understood, extra capacity may be the correct answer. A genuine growing dataset is different from an unbounded debug log. Keep working space for upgrades, database maintenance and temporary files rather than planning to run permanently at the limit.
| Requirement | HYEHOST option | Important distinction |
|---|---|---|
| Linux applications with root control | Cloud VPS | Manage your OS, logging and application retention |
| Off-server backup files | Storage Box | Managed remote storage, not an automatic extension of your root disk |
| A self-managed backup server or large archive VM | Storage VPS | Root-access KVM with capacity-focused HDD data storage |
Use a Storage Box with a supported backup client such as rclone over SFTP, or compare Restic, BorgBackup and Kopia. Upload, verify and test restoring before removing local recovery copies. Never move live database files to a remote file mount as an improvised space fix; use application-consistent backups or a planned migration.
Increasing a virtual disk allocation may still require guest partition, logical-volume or filesystem expansion. The correct procedure depends on your layout. Check lsblk -f, keep a backup and follow a layout-specific procedure instead of copying a generic resize command intended for another filesystem.
Disk-full recovery checklist
- The failing path and filesystem are identified.
- Both free bytes and inode usage have been checked.
- The data producer is understood and unnecessary growth is paused.
- Important data and required log history are protected before cleanup.
- Only a reviewed cleanup or retention change has been applied.
- Applications can write again and restarted services are healthy.
- Monitoring and retention are in place before normal jobs resume.
- Backups are independent and a restore has been tested.
Linux disk-full FAQs
Why does Linux say no space left on device when space is available?
The affected filesystem may have run out of inodes rather than bytes, or the application may be writing to a different mount, a full temporary filesystem or a container layer. Check the exact failing path with df -hT and df -i. Quotas and filesystem-specific limits may also need investigation.
Why is disk space still used after deleting a file?
A process can keep a deleted file open. The storage is normally released when its final open reference is closed. Use sudo lsof +L1 to identify candidates, then plan a supported reload or restart of the owning service.
Is docker system prune safe for a production VPS?
Not as a blind first step. It can remove stopped containers, unused networks, images and build cache. Adding volume-pruning options increases the risk of losing persistent data. Inspect usage and remove only objects you have confirmed are no longer needed.
Does adding more VPS storage fix inode exhaustion?
Not automatically. It depends on the filesystem and how it is expanded. Find the source of excessive small files, correct its retention policy and verify inode capacity after any storage change.
Should I use a Storage Box or a Storage VPS for backups?
A Storage Box suits managed remote file storage accessed with tools such as SFTP, rsync or backup clients. A Storage VPS provides a Linux VM with root access for a self-managed backup service. Neither replaces retention rules, encryption or restore testing.

