Move Docker to Separate Drive on Ubuntu

Every Linux server failure I’ve witnessed from disk issues starts the same way: the root filesystem slowly fills up. No alarms. No drama. Just creeping usage until something breaks.

On this Ubuntu server, / was sitting at a seemingly safe percentage — but something felt off. A quick disk usage scan revealed the real problem:

/opt  141G

A single directory consuming 141 GB on the root partition is a serious warning sign. On Docker hosts, the usual culprit is container storage — images, volumes, and build cache quietly accumulating under /var/lib/docker. Left unchecked, this growth will eventually take down your server.

Rather than wait for the root partition to fill and crash critical services, I made a structural fix: I moved Docker completely off the root disk. Here is exactly how I did it — and why every Ubuntu server running Docker should do the same.


How Docker Uses Disk Space

By default, Docker stores everything under a single directory on the root filesystem:

/var/lib/docker

This directory holds images, running and stopped containers, named and anonymous volumes, the build cache, and the overlay filesystem layers that make up each container’s writable layer. On an active system running multiple services, this storage can easily grow into hundreds of gigabytes without any obvious warning.

The core problem is that /var/lib/docker lives on the same partition as your operating system. When that partition fills up, the consequences cascade quickly: Docker stops launching containers, systemd cannot write state files, log rotation fails, and SSH may stop accepting new connections. In severe cases, the server becomes completely unresponsive and requires direct console access to recover — a nightmare scenario in production.

The fix is straightforward: move Docker’s data directory to a dedicated separate disk so that container storage growth can never starve the OS of the disk space it needs to function.


The Approach

Instead of periodically pruning images and hoping for the best, the right long-term solution is to relocate Docker’s data root to a secondary disk. Docker supports this natively through a single configuration option — data-root — in /etc/docker/daemon.json. No third-party tools required.

In this case, the secondary drive was already mounted at:

/mnt/1TB

The new Docker data path was set to:

/mnt/1TB/docker-data

Step-by-Step: Move Docker to Another Drive on Ubuntu


Step 1 — Confirm the Secondary Drive Is Mounted

Before making any changes, verify that your secondary disk is mounted and configured to remain mounted after a reboot. Skipping this check is the most common cause of failed migrations.

Check current mounts:

df -h

Confirm that your secondary disk appears at the intended mount path. Then verify it has a UUID-based entry in /etc/fstab so it mounts automatically on every boot:

cat /etc/fstab

If the drive is not listed in /etc/fstab, add it before continuing. Without a persistent mount entry, Docker will fail to start after the next reboot — and you may lose access to your containers entirely.


Step 2 — Stop Docker

Stop both the Docker daemon and its socket to ensure no containers are running and no processes are actively writing to /var/lib/docker. Copying live data can result in corruption.

sudo systemctl stop docker
sudo systemctl stop docker.socket

Step 3 — Create the New Docker Directory

Create the target directory on the secondary disk and apply the same ownership and permissions that Docker expects:

sudo mkdir -p /mnt/1TB/docker-data
sudo chown root:root /mnt/1TB/docker-data
sudo chmod 711 /mnt/1TB/docker-data

Step 4 — Copy Existing Docker Data

Use rsync to copy everything from the original directory to the new location. The -a flag preserves permissions, ownership, timestamps, and symlinks. The -P flag displays real-time progress, which is helpful given how large Docker data directories can be:

sudo rsync -aP /var/lib/docker/ /mnt/1TB/docker-data/

Important: The trailing slashes on both paths matter. Without them, rsync will create a nested docker subdirectory inside the target instead of copying the contents directly into it — causing Docker to fail on startup.


Step 5 — Configure Docker to Use the New Location

Edit Docker’s daemon configuration file:

sudo nano /etc/docker/daemon.json

Add the data-root setting pointing to the new directory:

{
  "data-root": "/mnt/1TB/docker-data"
}

If daemon.json already contains other settings — such as GPU runtime configuration or logging drivers — merge the data-root key into the existing JSON object rather than replacing the file. Save and close when done.


Step 6 — Rename the Old Docker Directory as a Backup

Rename — do not delete — the original directory. This preserves a rollback path in case anything goes wrong during the first restart:

sudo mv /var/lib/docker /var/lib/docker.bak

Step 7 — Start Docker

sudo systemctl start docker

Step 8 — Verify the New Location

Confirm that Docker is now reading from the new data root:

docker info | grep "Docker Root Dir"

The output should show:

Docker Root Dir: /mnt/1TB/docker-data

Then verify that your containers, images, and volumes all migrated successfully:

docker ps -a
docker images
docker volume ls

If anything looks missing or Docker fails to start, stop the service, restore /var/lib/docker.bak to /var/lib/docker, and troubleshoot before proceeding.


Step 9 — Clean Up After Verification

Once you have confirmed that everything is running correctly from the new location, remove the backup to reclaim space on the root partition:

sudo rm -rf /var/lib/docker.bak

Do not rush this step. Run your containers for at least a full day — ideally through a complete reboot cycle — before deleting the backup. There is no recovering the backup once it is gone.


Production-Safe Boot Protection

There is one critical issue that most migration guides overlook: boot order. If Docker starts before the secondary drive has finished mounting, it will silently recreate /mnt/1TB/docker-data as an empty directory on the root partition. Your containers will appear to have vanished, and you will be right back to filling up the root disk — except now the actual data is stranded on the secondary drive.

To prevent this, create a systemd drop-in override that explicitly tells Docker to wait for the secondary mount before starting:

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/override.conf

Add the following:

[Unit]
RequiresMountsFor=/mnt/1TB

Reload systemd to apply the change:

sudo systemctl daemon-reload

With this override in place, Docker will not start until the secondary drive is fully mounted. If the drive fails to mount for any reason — hardware fault, filesystem error, or misconfigured fstab — Docker stays stopped rather than silently corrupting your setup. This single safeguard has saved many production environments from confusing, hard-to-diagnose failures.


Final Result

After completing this migration:

  • The root partition stays stable regardless of how many images, containers, or volumes you accumulate over time.
  • Docker storage is fully isolated on its own dedicated disk, where it cannot interfere with OS operations.
  • Disk growth becomes predictable and easy to monitor independently.
  • Server stability improves significantly because the OS partition is no longer at risk from container sprawl.

This is not a cleanup tactic or a temporary fix — it is a deliberate infrastructure decision that eliminates the root cause of the problem entirely.


Takeaway

If you run Docker on Ubuntu and care about server uptime, do not leave /var/lib/docker on your root partition. Move it to a separate mounted volume using the data-root option, enforce a systemd mount dependency so Docker cannot start without the disk, and protect your OS partition from runaway container storage growth.

Disk space problems rarely announce themselves. They accumulate quietly in the background until something critical fails at the worst possible moment. Moving Docker to a dedicated drive is one of the simplest, most effective infrastructure improvements you can make — and it only takes about 20 minutes to implement correctly.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Secret Link