I have run my home server on Ubuntu for years, and my Docker stack grew to over a dozen containers running everything from media streaming to DNS filtering. When I started hitting issues with snap packages and unexpected kernel updates resetting my networking configs, I decided it was time to switch to Debian. The big fear was losing all my carefully tuned containers and volumes in the process.
After completing this migration twice (once on my main server, once on a backup box), I can tell you the process is more approachable than most forum threads suggest. The key is treating your Docker data and your operating system as two separate layers. In this guide, I will walk you through migrating from Ubuntu to Debian on a home server without losing your Docker stack, step by step, with the exact commands I used.
This guide covers backing up your containers, volumes, and compose files, installing Debian fresh, restoring everything, and verifying that every service comes back online. Whether you run a simple Plex setup or a full homelab with reverse proxies, the approach below keeps your data intact.
Table of Contents
Why Migrate From Ubuntu to Debian for a Docker Home Server?
Debian is the upstream base for Ubuntu, which means nearly everything that runs on Ubuntu runs on Debian without modification. The main reasons I and many homelab operators on r/selfhosted switched come down to three things: stability, simplicity, and no snaps.
Ubuntu pushes snap packages aggressively, including snap versions of tools like curl and apt itself in some cases. Snaps add a layer of complexity and auto-update behavior that can break Docker networking or consume unexpected resources. Debian ships a clean, snap-free environment with only traditional apt packages.
Debian Stable also has a longer support window with fewer surprise changes between releases. Ubuntu LTS moves fast even on the LTS track, with HWE kernels and feature backports that occasionally reset firewall rules or change network interface naming. Debian Stable changes less, which is exactly what you want for a server running critical services.
Reddit users who made the switch consistently report that Docker feels cleaner and more predictable on Debian. The bare metal install is leaner too, giving you more resources for your containers.
Ubuntu vs Debian for Docker Home Servers
Both distributions are excellent Docker hosts, but they differ in ways that matter for a long-running home server. Here is what I found after running both:
Package management: Both use apt, but Debian sticks closer to upstream with fewer patches and custom tooling layered on top.
Kernel cadence: Ubuntu pushes newer kernels faster via HWE stacks, while Debian Stable keeps a proven kernel for the full release cycle.
Snaps: Ubuntu integrates snaps deeply; Debian does not include snapd by default.
Docker installation: Docker installs identically on both using the official Docker apt repository.
Resource usage: A minimal Debian install uses less RAM and disk than a comparable Ubuntu Server install.
Support lifecycle: Debian Stable gets roughly 5 years of support per release; Ubuntu LTS gets 5 years of standard support plus optional Extended Security Maintenance.
For a Docker home server where you want things to stay predictable, Debian Stable wins on simplicity. If you need newer kernels or specific PPAs, Ubuntu may still be the better call.
Pre-Migration Checklist and Backup Strategy
Before touching your Ubuntu installation, document and back up everything related to your Docker stack. I cannot stress this enough: a clean backup is your safety net. Here is the checklist I followed, pulled from my own migration notes and verified against community recommendations.
1. Inventory Your Running Containers
Start by listing every running container and its status. This gives you a record to compare against after migration.
Run this command on your Ubuntu server:
docker ps -a --format "table {{.Names}}t{{.Image}}t{{.Status}}t{{.Ports}}" > ~/container-inventory.txt
Save this file off the server. Copy it to a USB drive, cloud storage, or another machine. Do the same with your volume list:
docker volume ls > ~/volume-inventory.txt
2. Document Network Configurations
Note your static IP, DNS servers, and any custom Docker networks. Take screenshots or copy the output of ip addr and docker network ls. If you use a reverse proxy with custom ports, write down every port mapping.
Also back up your firewall rules if you use ufw or iptables:
sudo iptables-save > ~/iptables-backup.rulessudo ufw status verbose > ~/ufw-status.txt
3. Prepare a Debian Installation USB
Download the latest Debian Stable netinst ISO. I used Debian 12 (Bookworm) for my migration. Flash it to a USB drive using dd or a tool like Rufus. Test that it boots before you wipe anything.
4. Set a Maintenance Window
Expect 2 to 4 hours of downtime depending on your volume sizes. Schedule it when no one in your household depends on the services, and make sure your backup of all Docker data is complete and verified before proceeding.
Backing Up Your Docker Stack
This is the most important section of the entire guide. Your goal is to capture every file Docker needs to recreate your setup: compose files, environment files, volume data, and the Docker daemon configuration.
Backing Up docker-compose Files and .env Files
If you follow best practice, your containers are defined in docker-compose.yml files somewhere on your server. My stack lives in /opt/stacks/ with subdirectories per service. Find where yours are and back up the entire directory tree.
sudo tar -czvf ~/docker-compose-backup.tar.gz /opt/stacks/ /home/*/.docker/
Include any .env files. These contain environment variables like database passwords and API keys that Docker Compose reads at startup. Losing them means manually reconstructing passwords.
Backing Up Docker Volumes
Volumes hold your persistent data: database contents, config files, media metadata. There are two types to handle. Named volumes are managed by Docker, while bind mounts are directories on your host.
For each named volume, use a temporary busybox container to export the contents:
docker run --rm -v my_volume:/data -v $(pwd):/backup busybox tar czvf /backup/my_volume.tar.gz /data
Repeat this for every named volume. For bind mounts, simply tar the host directories:
sudo tar -czvf ~/bind-mounts-backup.tar.gz /mnt/appdata/ /var/lib/docker/volumes/
Backing Up the Docker Daemon Configuration
If you customized your Docker daemon settings, back up the configuration file:
sudo cp /etc/docker/daemon.json ~/daemon.json
Also note any systemd overrides you created for the Docker service:
sudo tar -czvf ~/docker-systemd-backup.tar.gz /etc/systemd/system/docker.service.d/
Copy Everything Off-Server
Move all backup archives to external storage. I used an external USB drive plus an rsync copy to a second machine on my LAN. Verify the file sizes and checksums match before you proceed.
sha256sum ~/docker-compose-backup.tar.gz > ~/checksums.txtrsync -avz ~/docker-* user@backup-machine:/backups/migration/
Installing Debian on Your Home Server
With your backups verified and stored safely, boot the Debian netinst USB. During installation, a few choices matter for a Docker host.
Partitioning Considerations
I chose a simple partitioning scheme: a single root partition with ext4 and a swap partition sized to match my RAM. If you run large volumes, consider putting /var/lib/docker on a separate partition or a faster SSD. Docker stores all container layers, images, and volumes under that path by default.
For ZFS or BTRFS users, set up your pools now. But for most home servers, ext4 on LVM gives you flexibility to resize later without complications.
Software Selection
During the tasksel step, uncheck everything except SSH server and standard system utilities. You do not need a desktop environment or a web server package from the installer. We will install Docker manually from the official repository for the latest version.
Network Configuration
Set your static IP during installation or configure it afterward. Debian uses ifupdown or NetworkManager depending on your choices. I configured a static IP in /etc/network/interfaces to match what I had on Ubuntu, so my containers could bind to the same address after restoration.
Post-Install Updates
Once Debian boots, update the system fully before installing Docker:
sudo apt update && sudo apt full-upgrade -ysudo apt install -y curl wget git htop vim
Reinstalling and Configuring Docker on Debian
Docker installation on Debian is nearly identical to Ubuntu. The official Docker apt repository provides the latest version, which is preferable to the older package in Debian repositories.
Install Docker Engine
Add the Docker GPG key and repository:
sudo install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpgecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list
Then install Docker Engine, CLI, containerd, the build plugin, and Docker Compose:
sudo apt updatesudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Docker Compose v1 to v2 Note
If you were running the old docker-compose v1 (the Python-based standalone binary) on Ubuntu, this is a good time to switch to Docker Compose v2. The v2 plugin installs as docker compose (with a space, no hyphen) and is fully backward compatible with your existing compose files.
Most compose files need zero changes. The only breaking change I encountered was with the version: field at the top of compose files, which v2 ignores. You can safely leave it or remove it.
Restore Daemon Configuration
If you backed up a custom daemon.json, restore it now:
sudo cp ~/daemon.json /etc/docker/daemon.jsonsudo systemctl restart docker
Verify Docker is running: sudo systemctl status docker
Restoring Your Docker Stack on Debian
This is where your preparation pays off. Restoring is a matter of putting files back in the right places and recreating volumes before bringing containers up.
1. Restore Compose and Env Files
Extract your compose backup to the same path structure you used on Ubuntu:
sudo tar -xzvf ~/docker-compose-backup.tar.gz -C /
This recreates /opt/stacks/ (or wherever your files lived) with all docker-compose.yml and .env files intact.
2. Restore Named Volumes
For each named volume backup, create the volume first, then restore its contents:
docker volume create my_volumedocker run --rm -v my_volume:/data -v $(pwd):/backup busybox tar xzvf /backup/my_volume.tar.gz -C /
The -C / extracts to the root of the volume, matching the original layout. Repeat for every volume you backed up.
3. Restore Bind Mounts
Extract your bind mount backup to the same host paths:
sudo tar -xzvf ~/bind-mounts-backup.tar.gz -C /
Check ownership and permissions after extraction. Docker containers run as specific UID/GID values, and tar should preserve these. If containers fail to read their data, check file ownership with ls -la in each restored directory.
4. Bring Your Stack Up
Navigate to each service directory and start the containers:
cd /opt/stacks/portainerdocker compose up -d
Repeat for every service directory. Bring up databases and dependencies first, then application containers, then reverse proxies last. This ordering prevents connection errors during startup.
5. Recreate Custom Docker Networks
If you defined custom networks in your compose files, Docker Compose recreates them automatically when you run docker compose up. If you had manually created external networks, recreate them before starting services:
docker network create my_custom_net
Post-Migration Verification Steps
After bringing everything up, verify each service is healthy. I created a simple checklist that took about 20 minutes to work through.
Run
docker psand confirm every expected container shows as running.Check logs for errors:
docker logs --tail 50 container_namefor each service.Test connectivity from another device on your network for each exposed port.
Verify your reverse proxy (Traefik, Nginx Proxy Manager, Caddy) routes traffic correctly.
Confirm databases accept connections and queries return expected data.
Check that volumes have data:
docker exec container_name ls /datafor key containers.Verify automated restart behavior:
sudo systemctl rebootand confirm all containers come back up.
If everything passes, your migration is complete. Your Docker stack is now running on Debian with all data preserved.
Troubleshooting Common Docker Migration Issues
Most issues I encountered and saw reported in forums fall into a few predictable categories. Here are the fixes.
Containers Fail to Start After Restore
The most common cause is a missing volume or bind mount path. Check docker inspect container_name and verify every mount source exists. If a path is wrong, recreate the directory or fix the compose file.
Permission errors are the second culprit. If a container ran as UID 1000 on Ubuntu and your Debian user has a different UID, fix ownership: sudo chown -R 1000:1000 /path/to/data.
Network Connectivity Issues
If containers cannot reach the internet or each other, check that IP forwarding is enabled:
sysctl net.ipv4.ip_forward
If it returns 0, enable it: sudo sysctl -w net.ipv4.ip_forward=1 and add net.ipv4.ip_forward=1 to /etc/sysctl.conf.
Also verify iptables rules are not blocking Docker’s bridge traffic. Debian’s default firewall policy is permissive, but if you configured nftables, make sure Docker’s chains are present.
Docker Compose Command Not Found
If you typed docker-compose (with a hyphen) out of habit from v1, switch to docker compose (with a space) for v2. Optionally install a compatibility alias:
sudo apt install -y docker-compose-plugin (already done above)
Volume Data Appears Empty
This usually means the volume restore extracted to the wrong path. Re-extract using -C / so the archive contents land at the volume root. Check with docker run --rm -v my_volume:/data busybox ls -la /data.
Frequently Asked Questions
Which is better for a home server, Debian or Ubuntu?
For a Docker-based home server, Debian Stable is the better choice for most users. It is lighter, free of snaps, and changes less between releases. Ubuntu LTS is better if you need newer kernels or rely on specific PPAs. Both run Docker identically using the official Docker repository.
Can I keep my Docker data when changing Linux distributions?
Yes. Docker stores containers and volumes independently of the operating system. As long as you back up your docker-compose files, .env files, and volume data before switching, you can restore them on any Linux distribution that runs Docker.
How do I preserve Docker volumes when switching from Ubuntu to Debian?
Export each named volume using a temporary busybox container that tars the contents to a backup file. After installing Debian and Docker, recreate each volume and extract the backup into it. Bind mounts are simpler: just tar the host directories and extract them to the same paths on the new OS.
Is Docker still relevant in 2026?
Yes, Docker remains the most widely used container runtime for home servers and self-hosted setups. Alternatives like Podman exist, but Docker Compose and the Docker ecosystem have the largest community and tooling support for homelab environments.
Conclusion
Migrating from Ubuntu to Debian on a home server without losing your Docker stack comes down to one principle: separate your data from your operating system. Back up your compose files, .env files, and every volume. Install Debian clean. Reinstall Docker from the official repository. Restore your files and volumes to the same paths. Then bring your containers back up in dependency order.
The entire process took me about three hours end to end, including verification. Every container came back online with its data intact, and I have not looked back. If you follow the steps above, your move to Debian will leave your Docker stack untouched and your homelab running on a leaner, more predictable foundation.