Skip to content 99% OFF 🎉 Anniversary Sale 99% OFF Shared Hosting Use Code HURRYUP Claim Offer 99% OFF Hosting
99% OFF Hosting — Code HURRYUP
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting cPanel Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Call +91 75795 45488
Login
Hosting Panel — cPanel & Billing Console Panel — VPS Management
ALL SYSTEMS OPERATIONAL
VPS

Docker Filling Up Your VPS Disk? Here's the Real Fix

Getwebup 6 min read

Your VPS says the disk is full, df -h shows the root partition pinned at 100%, and you haven't touched a config file in weeks. If you're running Docker on that box, there's a good chance the containers themselves are the reason — not your app, not MySQL, not your logs. Docker is quietly one of the worst offenders for eating disk space on a VPS, and it does it in ways that don't show up if you're only checking the usual suspects.

Symptom: Disk Full, But You Can't Find the Files

This one trips people up because the usual disk-full checklist — /var/log, MySQL binlogs, old backups — comes back clean, and the disk is still full. A few tells that Docker is the culprit:

  • df -h shows / or /var near 100%, but du -h /var/log /home doesn't add up to anywhere close to that number
  • Containers keep restarting or crashing with no application-level error
  • docker: no space left on device when you try to pull an image or build one
  • The box has been running the same handful of containers for months with regular redeploys (CI/CD pipelines are especially bad about this)

Run this first to confirm Docker is actually the problem before you go further:

docker system df -v

That gives you a breakdown of images, containers, local volumes, and build cache — with sizes. If that output is in the tens of gigabytes and your app code is a few hundred megabytes, you've found it.

Cause: Where Docker Actually Hides the Bytes

Docker doesn't put everything in one obvious place, which is why manual du scans miss it. Here's what's usually responsible, in order of how often we see it:

1. Container logs with no size limit

By default, Docker's json-file logging driver does not rotate or cap log size. A chatty app container (verbose access logs, a crash-looping process printing stack traces every few seconds) can silently grow a single log file to tens of gigabytes. Check the worst offenders:

docker inspect --format='{{.LogPath}}' $(docker ps -q) | xargs du -h 2>/dev/null | sort -rh | head -10

2. Dangling and unused images

Every docker build or CI redeploy that doesn't clean up after itself leaves behind old, untagged image layers. Over months of deploys these pile up fast, especially with large base images (Node, Python with ML libraries, anything with a big node_modules or site-packages baked in).

3. The build cache

Multi-stage builds and BuildKit cache layers aggressively — that's the point, it speeds up rebuilds — but on a VPS with limited disk, that cache can quietly become the single largest consumer on the machine.

4. Orphaned volumes

docker-compose down without -v leaves named and anonymous volumes behind even after the containers are gone. Database containers (Postgres, MySQL-in-Docker, Redis with persistence) are the usual culprits since their volumes grow continuously.

5. The overlay2 storage driver's own overhead

Each image layer under /var/lib/docker/overlay2 is stored separately, so a stack of similar images (say, five versions of the same app image) doesn't dedupe as cleanly as you'd expect, especially across different base image versions.

Fix: Clean It Up Without Breaking Anything Running

Step 1 — See what you'd actually reclaim

Before deleting anything, dry-run it:

docker system df -v
docker image ls -a
docker volume ls

Step 2 — Remove unused images, containers, networks and build cache

This is safe on a running host — it only removes stopped containers and images/cache not referenced by anything currently running:

docker system prune -a -f

Important: the -a flag also removes images that aren't attached to any container, even if you were planning to reuse them for a redeploy later. If you have a CI pipeline that pulls a base image once and reuses the cache, skip -a and just run docker system prune -f instead.

Step 3 — Clear volumes separately, and carefully

Volumes hold data, so don't run this blindly on a production box. List orphaned ones first:

docker volume ls -f dangling=true

Inspect anything that looks like it belongs to a database before removing it. Once you're sure it's safe:

docker volume prune -f

Step 4 — Truncate runaway container logs immediately

If a specific container's log file is the emergency, you can truncate it live without restarting the container — the process still has the file handle open, so this is safe:

truncate -s 0 $(docker inspect --format='{{.LogPath}}' )

Prevention: Stop It From Filling Up Again

Cap log size at the daemon level

This is the single biggest fix. Set a default log rotation policy in /etc/docker/daemon.json so no container can grow an unbounded log file again:

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

Restart Docker for it to take effect:

systemctl restart docker

Note this only applies to new containers created after the change — existing ones keep their original logging config until recreated.

Schedule a weekly prune

A simple cron entry keeps things from creeping back up between manual checks:

0 3 * * 0 docker system prune -af --filter "until=168h" >> /var/log/docker-prune.log 2>&1

The until=168h filter only removes images and cache older than a week, so you don't nuke something your CI pipeline pulled yesterday and still needs.

Always tear down with volumes when you mean it

If a compose stack is genuinely being retired, use docker-compose down -v instead of a bare down so orphaned volumes don't get left behind.

Watch disk usage, not just uptime

Set up basic disk-usage monitoring — even a cron job that emails you past 80% usage — so this shows up as a warning instead of a 3am outage. On a Getwebup VPS you can also keep an eye on usage from the control panel dashboard rather than relying on SSH checks alone.

Quick Reference

CommandWhat it doesSafe on a live production box?
docker system df -vShows what's using space, broken down by typeYes — read-only
docker system prune -fRemoves stopped containers, dangling images, unused networks and cacheYes
docker system prune -afSame as above, plus all unused (not just dangling) imagesCaution — removes images not tied to a running container
docker volume prune -fRemoves volumes not attached to any containerCaution — check for database volumes first
docker builder prune -afClears the BuildKit build cacheYes, just slows the next build

None of this replaces keeping an eye on actual disk headroom — if you're consistently running Docker workloads close to the edge of your current plan, it's usually cheaper to resize the VPS than to babysit prune jobs every week.

Frequently asked questions

Is it safe to run docker system prune -a on a production server?

It's safe in the sense that it won't touch anything currently running — stopped containers, dangling images, and unused build cache only. The risk is removing images you were planning to reuse for a fast redeploy. If your CI/CD relies on cached base images, use plain docker system prune (without -a) or add an age filter like --filter "until=168h" so recent images survive.

Why doesn't df -h match what du shows when Docker is involved?

Docker stores data under /var/lib/docker using the overlay2 driver, and deleted-but-still-open log files (a container writing to a log file that got rotated but the process still holds the old file handle) can hold disk space that du won't show as belonging to any visible file. docker system df -v is the accurate way to see Docker's real footprint.

Will limiting log size in daemon.json affect containers that are already running?

No. The max-size and max-file settings in /etc/docker/daemon.json only apply to containers created after you restart the Docker daemon. Existing containers keep whatever logging config they were started with until you recreate them (docker-compose up -d --force-recreate works for this).

I ran docker volume prune and now a container won't start. What happened?

You likely removed a volume that was mounted by a stopped container Docker didn't recognize as 'in use' at prune time — dangling volume detection only tracks currently running or created containers, not ones referenced in a compose file that hasn't been started yet. If you have a backup or the volume was for a database, restore from your last backup; otherwise check docker-compose.yml for the expected volume name and recreate it before restarting the stack.

How much disk should I reserve for Docker on a VPS?

As a rough floor, keep at least 20-30% of your total disk free at all times for image pulls, build layers, and log growth between prune cycles. If you're running more than a handful of containers or doing frequent CI builds on the same box, budget more — or move build/CI to a separate runner and keep the VPS for running the final images only.

#docker #vps #disk-space #docker-prune #log-rotation #overlay2

Keep reading

Chat with Support