$docker.recipes
·12 min read·Updated February 2026

Migrating Your Entire Docker Compose Stack to a New Server

A step-by-step playbook for moving all your Docker services, volumes, and configurations to new hardware with minimal downtime.

docker-composemigrationbackupdevops

01Server Migrations Don't Have to Be Scary

I've migrated my Docker Compose stack between servers three times: once for a hardware upgrade, once when switching VPS providers, and once when recovering from a drive failure. The first time was painful — 6 hours of downtime and a missed database backup. The third time took 45 minutes with zero data loss. The difference was having a repeatable migration playbook. This guide is that playbook, refined through real migrations. It works whether you're moving between physical servers, VPS providers, or even architectures (amd64 to arm64).

02Step 1: Inventory and Preparation

Before touching anything, document what you're running:
[terminal]
1# List all running containers and their compose projects
2docker ps --format "table {{.Names}} {{.Image}} {{.Status}}"
3
4# List all volumes and their sizes
5docker system df -v | grep -A 1000 "VOLUME NAME"
6
7# List all networks
8docker network ls
9
10# Export a list of all images (for pre-pulling on new server)
11docker images --format "{{.Repository}}:{{.Tag}}" | sort -u > images.txt
12
13# Find all compose files
14find /home -name "docker-compose.yml" -o -name "docker-compose.yaml" 2>/dev/null

Create this inventory before you need it. I run this script monthly and save the output alongside my backups. When migration day comes, you know exactly what needs to move.

03Step 2: Backup Everything

The critical backup targets: Compose files and .env files: These are your infrastructure definition. Copy every docker-compose.yml, .env file, and custom config file. Database dumps: Always take logical backups (pg_dump, mysqldump) in addition to volume backups. They're more portable and can restore across different versions. Docker volumes: Back up all named volumes. For large volumes (media libraries), consider rsync for incremental transfers.
[terminal]
1# Backup all compose files and configs
2tar czf compose-configs.tar.gz ~/docker/
3
4# Dump all PostgreSQL databases
5for db in nextcloud gitea; do
6 docker exec ${db}-db pg_dumpall -U postgres | \
7 gzip > ${db}-postgres.sql.gz
8done
9
10# Backup volumes (stop services first for consistency)
11docker compose -f ~/docker/nextcloud/docker-compose.yml stop
12tar czf nextcloud-data.tar.gz \
13 /var/lib/docker/volumes/nextcloud_data/
14docker compose -f ~/docker/nextcloud/docker-compose.yml start

04Step 3: Set Up New Server and Restore

On the new server, install Docker, restore configs, pre-pull images, restore volumes, and start services:
[terminal]
1# Install Docker on new server
2curl -fsSL https://get.docker.com | sh
3
4# Copy backups to new server
5rsync -avz backups/ newserver:~/migration/
6
7# Restore compose files
8tar xzf compose-configs.tar.gz -C ~/
9
10# Pre-pull all images (reduces startup time)
11while read image; do docker pull "$image"; done < images.txt
12
13# Create shared networks
14docker network create proxy
15
16# Restore volumes and start services
17# (reverse proxy first, then databases, then apps)
18cd ~/docker/traefik && docker compose up -d
19cd ~/docker/nextcloud && docker compose up -d

05Step 4: Verify and Switch DNS

Before switching DNS, verify everything works on the new server by accessing services directly via IP or by editing your local hosts file. Check that data is intact: log into each service and verify recent data exists. Check that databases restored correctly. Verify that file uploads and media libraries are complete. Once verified, update your DNS records to point to the new server's IP. If you're using Cloudflare Tunnels, update the tunnel to connect from the new server. Keep the old server running for at least a week in case you need to fall back. The entire process — backup, transfer, restore, verify — can be done with under 30 minutes of downtime if you prepare everything in advance. The key is doing the data transfer while the old server is still running, then doing a final incremental sync before switching over. Check out our operations docs and storage recipes for more backup and migration tooling.

Don't decommission the old server until you've verified everything on the new one works correctly for at least a week. Data loss during migration is usually discovered days later, not immediately.

About the Author

Frank Pegasus

DevOps engineer and self-hosting enthusiast with over a decade of experience running containerized workloads in production. Creator of docker.recipes.