A full disk rarely announces itself at a convenient time. A web application may stop writing uploads, a database may fail to start, or SSH login may become unreliable because the system cannot create temporary files. The tempting response is to delete the largest directory you can find. That is also how administrators remove valuable logs, damage application data, or discover that deleting files did not recover any space at all.
This guide presents a safer workflow: measure the filesystem, determine whether blocks or inodes are exhausted, identify the largest owners, clean known caches deliberately, and verify the result. The commands work across Ubuntu and Debian, RHEL and Fedora, and AlmaLinux, with distro-specific differences called out.
TL;DR
- Run
df -hTanddf -ihto distinguish full storage from exhausted inodes. - Use
duon the affected mount, not the entire server, to locate large directories. - Clean package caches and old systemd journal data with supported tools.
- Check for deleted files still held open by running processes with
lsof +L1. - Restart or reload the responsible service only after confirming what owns the file.
- Run the disk and inode checks again, then test the affected application.
Why disk-space management matters
Linux needs free space for package transactions, logs, sockets, temporary files, database journals, and service metadata. A filesystem at 100 percent capacity can cause failures well before a server appears completely unusable. Separate mounts make the situation less obvious: /var may be full while the root filesystem still has room, or a small boot partition may be the only exhausted mount.
Space can also be consumed by thousands of tiny files. In that case, the filesystem has free gigabytes but no free inodes, so creating one more file fails with an error such as No space left on device. Diagnosis must come before cleanup.
Prerequisites and safety rules
- Have a shell with
sudoaccess. Become root only when necessary. - Know whether the server has maintenance, backup, retention, or compliance requirements.
- Run destructive cleanup during an approved window if a production service may be restarted.
- Do not delete unknown files under
/var/lib, database directories, container storage, or application data. - Do not run broad commands such as
rm -rf /var/log/*orrm -rf /tmp/*as a first response.
1. Diagnose the affected filesystem first
Start with mounted filesystem usage:
df -hT
The -h flag makes sizes readable, while -T adds the filesystem type. A typical result looks like this:
Filesystem Type Size Used Avail Use% Mounted on
/dev/vda2 ext4 40G 38G 1.1G 98% /
tmpfs tmpfs 512M 0 512M 0% /run/user/1000
Focus on a real disk mount with a high percentage, such as /, /var, or /home. Ignore pseudo-filesystems such as tmpfs unless a specific workload intentionally uses them. If a mount is 95 percent full but your application is failing now, continue investigating rather than waiting for it to reach 100 percent.
Now check inode usage:
df -ih
Look at the IUse% column. If it is 100 percent while Avail in the first command is still large, the problem is too many files, not too many bytes. Mail queues, session files, cache entries, and badly configured temporary-file jobs are common causes.
For a quick view of mounted block devices and mount points, use:
lsblk -f
Expected output includes device names, filesystem types, labels, UUIDs, and mount points. This prevents investigating /dev/vda2 when the full mount is actually a separate /dev/vda3 mounted at /var.
2. Find what consumes the bytes
Run du against the affected mount. The example below examines the root filesystem without crossing into other mounted filesystems:
sudo du -xhd1 / 2>/dev/null | sort -h
Here, -x stays on one filesystem, -h formats sizes, and -d1 limits the scan to one directory level. 2>/dev/null hides permission warnings; remove that redirect when you need to investigate every error. Expected output may resemble:
180M /boot
2.4G /home
7.8G /usr
21G /var
38G /
Repeat the command on the largest directory. For example:
sudo du -xhd1 /var 2>/dev/null | sort -h
Common findings include /var/log, /var/cache, /var/lib/containers, /var/lib/docker, package metadata, or an application-specific directory. To find unusually large individual files without scanning other mounts, use:
sudo find /var -xdev -type f -size +500M -printf '%s %p
' 2>/dev/null | sort -n | tail -20
-xdev prevents crossing filesystem boundaries, -type f selects regular files, and -size +500M filters files larger than 500 mebibytes. The output starts with the size in bytes and ends with the path. A large active database file is expected; do not remove it merely because it appears in this list.
3. Check for the deleted-open-file trap
Sometimes du reports little usage, but df reports a full filesystem. A process may still hold a deleted log or temporary file open. The directory entry is gone, so du cannot see it, but the kernel keeps the blocks allocated until the process closes the file.
sudo lsof +L1
Look for a regular file with a DEL marker and a large size. A simplified result might look like:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NAME
java 18422 app 7w REG 252,0 4294967296 0 /var/log/app.log (deleted)
Record the command, PID, service, and file size. Prefer a graceful service restart rather than killing the process. For a systemd service, first identify its status:
sudo systemctl status app.service --no-pager
Then restart it only if you understand the service impact:
sudo systemctl restart app.service
Verify that the deleted-open entry is gone and rerun df -hT. If the service cannot be restarted immediately, coordinate with the application owner. Truncating an open log can be appropriate in an emergency, but it is service-specific and should not be used on database or application data files.
4. Clean package-manager caches safely
Ubuntu and Debian
First inspect the package cache:
sudo du -sh /var/cache/apt/archives
Use APT’s supported cleanup operation:
sudo apt-get clean
This removes downloaded package archives from the local cache but does not uninstall installed packages. To remove only obsolete archives, use sudo apt-get autoclean. Do not confuse this with sudo apt-get autoremove, which can remove packages considered no longer required; review its proposed package list before confirming.
RHEL, Fedora, and AlmaLinux
DNF stores metadata and downloaded packages under locations such as /var/cache/dnf. Inspect and clean it with:
sudo du -sh /var/cache/dnf
sudo dnf clean packages
clean packages removes cached RPM packages. If metadata is also unusually large or corrupted, use sudo dnf clean all; the next package operation will download fresh metadata. Older RHEL or minimal installations may provide YUM instead:
sudo yum clean all
On Fedora, avoid deleting DNF cache directories manually while another package transaction is running. Package caches are normally safe to rebuild, but cleaning them does not fix a workload that is continuously generating data.
5. Reduce systemd journal growth
Check how much persistent journal data is present:
sudo journalctl --disk-usage
Example output:
Archived and active journals take up 3.2G in the file system.
To remove archived entries older than fourteen days, use:
sudo journalctl --vacuum-time=14d
Alternatively, remove archived data until the journal is below a size limit:
sudo journalctl --vacuum-size=500M
These commands target archived journal files; they do not erase every current event. Choose retention based on incident-response and compliance needs. If logs are needed for a security investigation, export or archive them before vacuuming.
Prevent recurrence by setting a persistent limit. Create a small drop-in configuration:
sudo mkdir -p /etc/systemd/journald.conf.d
printf '[Journal]\nSystemMaxUse=500M\nRuntimeMaxUse=100M\n' | sudo tee /etc/systemd/journald.conf.d/limits.conf
sudo systemctl restart systemd-journald
SystemMaxUse limits persistent journals, while RuntimeMaxUse limits journals stored in memory-backed runtime storage. The exact limit should reflect disk size, log volume, and your retention policy. See the related AdminHint guide on managing systemd logs with journalctl for filtering and forwarding details.
6. Investigate logs and application data without guessing
List the largest log directories before touching them:
sudo du -xhd1 /var/log 2>/dev/null | sort -h
On systems using logrotate, inspect rotation configuration and status:
sudo logrotate -d /etc/logrotate.conf
The -d flag performs a debug run without changing files. If rotation is overdue, do not immediately force it on a busy production server. Check the relevant service and schedule, then use sudo logrotate -f /etc/logrotate.conf only when you understand the consequences.
For Docker or Podman hosts, container logs and image layers may dominate usage. List containers before removing anything:
sudo docker system dfsudo podman system df
Review the output carefully. Commands such as docker system prune and podman system prune can remove unused images, stopped containers, and build data. They are not harmless cache commands on a production host. Confirm that stopped containers and untagged images are disposable, and preserve required images or volumes first.
7. If inodes are exhausted
When df -ih shows 100 percent inode usage, locate directories containing huge numbers of files. This count-only scan is useful, although it can take time:
sudo find /var -xdev -type f -printf '%h
' 2>/dev/null | sort | uniq -c | sort -n | tail -20
It prints directory paths and the number of regular files found beneath each direct parent. Typical causes include abandoned session files, mail queues, application cache keys, or a job creating one file per event.
Do not use a wildcard deletion without confirming the path and retention rule. Fix the producing application, configure bounded retention, and remove files with a tool that understands age or ownership. For example, after confirming that old files in a dedicated cache directory are safe:
sudo find /srv/example-cache -type f -mtime +14 -print
The first command is a preview. Only after reviewing it should you add -delete:
sudo find /srv/example-cache -type f -mtime +14 -delete
-delete, preview the result, and never run an unreviewed find / -delete. A typo or incorrect mount can remove system files.8. Verify the cleanup
Run the original measurements again:
df -hT
df -ih
sudo du -xhd1 / 2>/dev/null | sort -h
sudo lsof +L1
Successful cleanup should show more available blocks or inodes. If df improves but du still appears inconsistent, check for deleted-open files again. If du identifies a directory that remains large, the data is still present; cleanup may have removed only a cache or old journal files.
Finally, test the service that originally failed. Check its status and recent errors:
sudo systemctl is-active nginx
sudo journalctl -u nginx -n 30 --no-pager
Replace nginx with the affected service. A healthy result from systemctl is-active is active. Also test the application endpoint, package installation, scheduled jobs, or database connection that exposed the problem.
Common mistakes
- Scanning across mounts: A plain
du -sh /*can descend into network filesystems, container mounts, or virtual paths. Use-xfor the affected filesystem. - Deleting active logs: Removing a log path does not release space while a process still has it open. Use service-aware rotation or restart the owner.
- Cleaning the wrong filesystem: Always compare the path with
df -hT. A large directory on another mount may not help the full filesystem. - Ignoring the cause: A one-time cleanup is not a fix if a runaway debug log, failed rotation job, or unbounded cache continues growing.
- Using
rm -rfunder system directories: Package databases, databases, and container storage require their own management tools.
Best-practice checklist
| Task | Command or decision | Why |
|---|---|---|
| Measure blocks | df -hT |
Find the full mount and filesystem type. |
| Measure inodes | df -ih |
Detect too many small files. |
| Find large areas | du -xhd1 /mount | sort -h |
Stay on the affected filesystem. |
| Check hidden allocation | lsof +L1 |
Find deleted files held open. |
| Clean supported caches | APT or DNF cleanup | Avoid corrupting package state. |
| Verify | Repeat df, then test the service |
Prove both capacity and functionality recovered. |
For broader storage planning, connect this workflow with an AdminHint guide to Linux disk monitoring and alerts. Prevention is better than emergency deletion: alert before 80 or 90 percent usage, monitor inode percentages, configure log retention, and leave enough free space for package updates and recovery operations.
Conclusion
Safe Linux disk cleanup is an investigation, not a single deletion command. Start with df, determine whether blocks or inodes are exhausted, use du and lsof to identify the real owner, and use package-manager and journal tools for supported cleanup. Treat application data, container storage, and database files as protected until their owners approve an action. Recheck capacity and test the service after every change. This method works consistently on Ubuntu, Debian, RHEL, Fedora, and AlmaLinux while keeping recovery safer and more repeatable.
FAQ
Can I delete everything in /var/log?
No. Logs may be needed for operations, security, or compliance, and deleting active logs may not release space. Inspect usage, use journal vacuuming or logrotate, and coordinate service handling.
Why did deleting a large file not free space?
A running process may still have the file open. Find it with sudo lsof +L1, then gracefully restart or reload the owning service when appropriate.
Is apt-get clean safe?
It removes downloaded package archives, not installed packages. It is generally safe, but it will require packages to be downloaded again later.
What if the filesystem fills again immediately?
Watch the suspected directory with repeated du checks, inspect service logs and timers, and identify the process generating data. Correct retention, rotation, or application configuration rather than repeating emergency cleanup.