
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Running out of storage is one of the most common causes of unexpected downtime on Linux servers. When you need to free disk space on Ubuntu, the priority is identifying safe targets like package caches, rotated logs, and orphaned containers before touching application data. This guide provides the exact diagnostic and cleanup workflow I use in production environments to recover gigabytes quickly without risking service stability or data integrity.
sudo du -ahx / | sort -rh | head -20 to identify large files on the root partition. Then run sudo apt autoremove --purge, sudo journalctl --vacuum-size=100M, and docker system prune -a to reclaim space from packages, logs, and containers respectively.How do you accurately diagnose disk usage before cleaning?
Before deleting anything, you must distinguish between actual disk consumption and inode exhaustion, as they require completely different remediation strategies. A common mistake engineers make when trying to diagnose high resource usage is assuming that a "No space left on device" error always means the disk is physically full. In reality, your filesystem might have plenty of bytes available but zero free inodes, which happens frequently on mail servers or systems generating millions of small temporary files.
Start with df -h to see human-readable filesystem usage and df -i to check inode utilization. If inodes are at 100% but disk usage shows only 40%, you have a small-file problem. Use find /var -xdev -type f | wc -l to count files in suspect directories. For byte-level analysis, always use the -x flag with du to avoid traversing into mounted volumes like /proc, /sys, or separate data partitions. The command sudo du -ahx / | sort -rh | head -20 gives you the twenty largest items strictly on the root filesystem, which is usually where the emergency lies.
A third scenario catches many engineers off guard: files that have been deleted but are still held open by running processes. The space won't be released until the process closes the file descriptor or restarts. Check this with sudo lsof +L1 | grep deleted. If you see multi-gigabyte log files in this output, restarting the relevant service (often rsyslog, nginx, or a Java application) will instantly reclaim that space without any manual deletion.
How do you safely clean APT caches and old kernels on Ubuntu?
The Advanced Package Tool (APT) accumulates significant debris over time. On long-lived servers, especially those receiving regular security patches, the package cache and orphaned dependencies can consume several gigabytes. This is typically the safest place to begin when you need to free disk space on Ubuntu because these operations are fully reversible through reinstallation.
- Purge removed packages: Run
sudo apt autoremove --purge. The--purgeflag is critical; without it, configuration files remain on disk even after the package binaries are removed. This single command often recovers 500MB to 2GB on neglected systems. - Clean the package cache: Execute
sudo apt cleanto remove all cached.debfiles from/var/cache/apt/archives/. Unlikeapt autoclean(which only removes obsolete versions),apt cleanempties the entire cache. Since packages can be re-downloaded on demand, this is safe for production. - Remove old kernels: Ubuntu retains previous kernel versions for rollback safety. List installed kernels with
dpkg --list | grep linux-image. Never remove the currently running kernel (uname -r). Remove older versions withsudo apt purge linux-image-X.X.X-XX-generic. On systems that haven't been cleaned in years, this alone can free 3–5GB. - Clean residual configs: Find packages in "rc" state (removed but config remains) using
dpkg -l | grep ^rc. Purge them all at once withdpkg -l | grep ^rc | awk '{print $2}' | sudo xargs dpkg --purge.
Always verify your bootloader configuration after kernel removal by running sudo update-grub. While APT handles this automatically in most cases, confirming ensures you don't accidentally boot into a missing kernel during the next maintenance window.
What is the correct way to manage systemd journal and log rotation?
Systemd journals are a frequent silent consumer of disk space. By default, journald may store up to 10% of your filesystem size in binary logs under /var/log/journal/. On a 100GB root partition, that's potentially 10GB of logs you may never query. Proper log rotation and disk management prevents this from becoming a recurring crisis.
<!-- Check current journal usage -->
journalctl --disk-usage
<!-- Vacuum to a specific size limit -->
sudo journalctl --vacuum-size=100M
<!-- Or retain only recent time period -->
sudo journalctl --vacuum-time=7d
<!-- Make persistent configuration change -->
sudo nano /etc/systemd/journald.conf
# Set: SystemMaxUse=100M
# Set: MaxRetentionSec=1week
sudo systemctl restart systemd-journald Beyond journald, check traditional text logs in /var/log/. Applications writing verbose debug output can generate massive files between logrotate cycles. Use sudo find /var/log -type f -size +100M to locate oversized logs. Before truncating active log files, never use rm; instead use truncate -s 0 /var/log/filename.log or redirect with : > /var/log/filename.log. Deleting an open file doesn't free space until the writing process releases its handle, whereas truncation works immediately while preserving the inode the process expects.
Review your logrotate configuration in /etc/logrotate.d/. Ensure compression is enabled (compress directive) and retention periods match your compliance requirements. For SOC 2 or ISO 27001 environments, you may need longer retention; configure offsite shipping to S3 or a centralized logging stack so local retention stays lean. If you're running workloads that benefit from AI-powered log analysis, ship logs externally rather than hoarding them locally.
How should you handle Docker and container storage cleanup?
Docker is frequently the single largest consumer of disk space on modern Ubuntu servers. Unused images, stopped containers, dangling build cache, and orphaned volumes accumulate silently. On CI runners and development servers, Docker can easily consume 50–100GB within weeks if not managed proactively.
| Command | What It Removes | Risk Level | Typical Recovery |
|---|---|---|---|
docker container prune | Stopped containers only | Low | 100MB–2GB |
docker image prune -a | All unused images (not just dangling) | Medium | 5–30GB |
docker volume prune | Unnamed volumes not attached to containers | High | 1–50GB |
docker builder prune | BuildKit cache layers | Low | 2–20GB |
docker system prune -a --volumes | All of the above combined | High | 10–80GB |
The aggressive docker system prune -a --volumes command is powerful but dangerous. It removes anonymous volumes that may contain database state from improperly configured compose stacks. Always list volumes first with docker volume ls and inspect suspicious ones with docker volume inspect <name> before pruning. For production systems, prefer targeted cleanup: prune stopped containers and dangling images first, then address volumes individually.
For ongoing management, configure Docker's log driver to prevent container logs from growing unbounded. Add "log-driver": "json-file" and "log-opts": {"max-size": "10m", "max-file": "3"} to /etc/docker/daemon.json. Without this, a single verbose container can fill your disk overnight. Teams adopting Docker containerization should bake these defaults into their base server provisioning from day one.
When should you automate disk space monitoring versus manual cleanup?
Reactive cleanup works for emergencies, but sustainable operations require proactive monitoring. If you're manually freeing disk space on Ubuntu more than once per quarter, you need automation. The threshold depends on your growth rate and operational tolerance; I recommend alerting at 75% usage and taking automated action at 85%.
- Set up monitoring alerts: Use node_exporter with Prometheus, or CloudWatch Agent on AWS, to track
node_filesystem_avail_bytes. Configure alerts at 75% (warning) and 85% (critical). This gives you hours or days to respond instead of minutes. - Automate safe cleanup via cron: Schedule
apt autoremove --purgeandjournalctl --vacuum-size=100Mweekly. These are idempotent and risk-free. Do not automatedocker system pruneor volume cleanup without explicit approval workflows. - Implement log shipping: Rather than retaining months of logs locally, ship to a centralized platform. This aligns with ELK stack best practices and keeps local disk usage predictable regardless of traffic spikes.
- Right-size your volumes: If you're consistently above 70% usage even after cleanup, your provisioning is wrong. Expand the volume or migrate to larger storage. Disk is cheap; outage recovery is expensive.
For teams managing multiple servers, consider infrastructure-as-code approaches to enforce consistent disk hygiene. Tools like Ansible can deploy standardized logrotate configs, journald settings, and cleanup cron jobs across your fleet. This eliminates configuration drift that inevitably leads to one server silently filling up while others remain healthy. If you're building new infrastructure, integrating these patterns during initial server setup prevents technical debt from accumulating in the first place.
Sustainable Disk Hygiene for Production Ubuntu Servers
Freeing disk space on Ubuntu is straightforward when you follow a methodical diagnostic-first approach. Start with safe, reversible operations like APT cache cleaning and journal vacuuming before progressing to higher-risk targets like Docker volumes and manual file deletion. Automate the safe operations, monitor proactively, and treat repeated emergencies as a signal to fix underlying architecture rather than just cleaning up symptoms. If your team needs help establishing sustainable disk management practices or auditing existing infrastructure for compliance readiness, reach out to discuss your environment.