Skip to content

Disk Cleanup β€” Reclaiming Space on Linux Servers

Last reviewed: 2026-09-17

Purpose: A practical workflow for finding and reclaiming disk space on Linux hosts, with emphasis on Docker artefacts, container logs, qcow2 virtual machine images, and system logs. See also the step-by-step walkthrough in UbuntuDiskCleanUp.md.


1. Diagnose Before Deleting

Find the filesystem that is actually full, then walk down the directory tree towards the culprit. Deleting without measuring wastes time and risks removing something in use.

df -h                          # which filesystem is full
df -i                          # inode exhaustion looks identical to "disk full"
du -xh / --max-depth=1 | sort -h    # top-level consumers (stay on one filesystem)
du -xh /var --max-depth=2 | sort -h | tail -20
du -xh /var/lib --max-depth=1 | sort -h

du -x stays on one filesystem, so it does not descend into mounted volumes. Alternatively use ncdu /var, which gives an interactive, navigable view β€” much faster for hunting space than repeated du calls.

Two common traps: a deleted-but-open file still holds its blocks until the process exits (sudo lsof +L1 lists them), and inode exhaustion on filesystems with millions of small files reports free space while refusing new writes.


2. Docker

Docker typically accounts for the largest recoverable amount on an application host: stopped containers, superseded image layers, orphaned volumes, and build cache.

docker system df                   # space used vs. reclaimable, by category
docker system df -v                # per-image, per-container, per-volume breakdown

docker container prune             # stopped containers
docker image prune                 # dangling (<none>) images
docker image prune -a              # all images not referenced by a container
docker builder prune               # build cache
docker volume prune                # volumes not used by any container
docker network prune               # unused networks

# Everything at once β€” read the confirmation prompt
docker system prune -a --volumes

Reclaim build cache selectively rather than wholesale when builds are frequent:

docker builder prune --filter until=168h    # drop cache older than 7 days
docker builder prune --keep-storage 10GB    # keep the most recent 10 GB of cache

Container logs

The json-file log driver writes to /var/lib/docker/containers/<id>/<id>-json.log and, unconfigured, grows without limit. Truncate a log that is already filling the disk:

sudo truncate -s 0 /var/lib/docker/containers/<container-id>/<container-id>-json.log

Then prevent recurrence by capping log size globally in /etc/docker/daemon.json and restarting the daemon:

{
  "log-driver": "json-file",
  "log-opts": { "max-size": "100m", "max-file": "3" }
}

Existing containers keep their old logging settings; recreate them for the cap to apply.


3. KVM / libvirt Virtual Machines

Virtual machine disk images are usually the single largest consumer on a virtualisation host. Two separate things must be kept under control: images belonging to deleted VMs, and qcow2 files that have grown beyond the space actually used inside the guest.

virsh list --all                        # defined VMs, running or not
virsh domblklist <vm>                   # disks attached to a VM
qemu-img info /var/lib/libvirt/images/<vm>.qcow2    # virtual vs. actual size

Remove a VM together with its storage:

virsh destroy <vm>                      # stop if running
virsh undefine <vm> --remove-all-storage

Find orphaned images no longer referenced by any VM definition, then delete them deliberately:

for f in /var/lib/libvirt/images/*.qcow2; do
  virsh domblklist --all $(virsh list --all --name) 2>/dev/null | grep -q "$(basename "$f")" \
    || echo "unreferenced: $f"
done

Compacting a qcow2 image (internal snapshots permitting) frees space the guest once wrote but no longer uses:

# 1. Inside the guest: fill free space with zeros so they can be discarded
sudo dd if=/dev/zero of=/zero.fill bs=1M status=progress; sudo rm -f /zero.fill

# 2. On the host: rewrite a sparse copy that only stores allocated zeroes
sudo qemu-img convert -O qcow2 -c /var/lib/libvirt/images/vm.qcow2 \
  /var/lib/libvirt/images/vm-compact.qcow2
sudo mv /var/lib/libvirt/images/vm-compact.qcow2 /var/lib/libvirt/images/vm.qcow2

Interpretation of qemu-img info: when the disk size is close to the virtual size, the guest really is using the space and only guest-side cleanup will help. When the disk size is far below the virtual size, the image is sparse and compaction reclaims the difference.


4. System Logs, Caches and Packages

Journal logs are usually capped already, but a log storm can push them far beyond the default.

journalctl --disk-usage                  # how much the journal currently holds
sudo journalctl --vacuum-time=7d         # keep only the last 7 days
sudo journalctl --vacuum-size=500M       # or cap by total size

# /etc/systemd/journald.conf
# SystemMaxUse=500M

Other routine targets:

sudo apt clean            # clear downloaded .deb archives in /var/cache/apt
sudo apt autoremove       # remove packages no longer required
snap list --all | awk '/disabled/{print $1, $3}'    # old snap revisions
sudo du -xh /var/log --max-depth=1 | sort -h
sudo find /var/log -type f -name '*.gz' -delete     # rotated compressed logs no longer needed

Old kernels, crash dumps in /var/crash, and package caches in /var/cache/ are frequent offenders on hosts that have been running for years.


5. Where the Space Actually Is

Target Typical gain Risk
Unused VMs and their images Very large Low if the VM is genuinely retired
Inside the guests (old logs, package caches, docker system prune) Large Low
qcow2 compaction Large, but slow Low; do not use -c on images with active internal snapshots
Docker volumes Variable High β€” --volumes deletes data with no container referencing it
Journal and rotated logs Usually modest Low
apt / snap / package caches Modest Low

On multi-terabyte hosts, logs are rarely the problem: the wins come from retiring virtual machines, cleaning inside running guests, and pruning container artefacts. Measure first, delete second, and never run a destructive prune on a host whose backups have not been verified.