3v-Hosting Blog

How to Migrate Docker Compose to a New VPS Without Downtime

Administration

16 min read


In most cases, moving to a new VPS is done for a serious and practical reason - for example, your project has grown beyond the capacity of your current resources, your project requires more powerful hardware, you’re switching data centers, or it’s time to upgrade your infrastructure. If the application runs on Docker Compose, this task seems fairly simple at first glance - after all, all you need to do is copy the files, start the containers, and you’re done.

But in reality, it is precisely this oversimplified view that ultimately leads to downtime, data loss, or unexpected application behavior. Of course, Docker significantly simplifies infrastructure migration, but it does not relieve the administrator of the need to properly organize the migration process itself.

There’s good news, too. It’s that a Docker Compose migration can be carried out virtually transparently to users. However, to achieve this, it’s important to view migration not as simply copying containers, but as moving the entire application runtime environment - including configurations, the data itself, network settings, and the environment.

In this article, we’ll walk through a step-by-step process that allows you to migrate your Docker Compose project to a new VPS with minimal downtime - or none at all.

 

 

 

Prepare the new server in advance

As counterintuitive as it may seem, one of the most common mistakes made during migration is to shut down the old VPS and only then begin configuring the new one. This approach directly leads to downtime. Obviously, the only correct approach is to keep both servers running during the migration and to shut down the old server only after the new environment is fully prepared and the project has been switched over to it.

Before moving the project to the new server, you need to complete several preparatory steps on it:

  • update the operating system;
  • install Docker Engine;
  • install the Docker Compose Plugin;
  • configure the firewall;
  • prepare directories for persistent data;
  • ensure that the VPS has sufficient resources to run the project with some headroom.

 

You can check the installed Docker versions using the following commands:

docker --version
docker compose version
docker info

If the project uses modern Docker features, such as BuildKit, it makes sense to verify in advance that the new version of Docker Engine supports them - after all, it’s better to detect incompatibilities before starting the migration than after the containers have already been launched.

There’s one more point that’s very easy to overlook. Check the architecture of the new server. If the old VPS ran on x86_64 (amd64) and the new one uses ARM, some images may simply fail to start. This is especially true for custom builds or projects that use third-party images that are rarely updated.

Once you’ve upgraded the server and performed the necessary checks, you can proceed with the step-by-step project migration.

 

 

 

 

Migrate the infrastructure, not just the application

A common mistake in many migrations is copying only the application files to the new VPS and then immediately trying to start the containers. This is almost never enough, since the entire project environment must be prepared before the first launch. Typically, this involves the following files and components:

  • docker-compose.yml;
  • .env;
  • custom Dockerfile;
  • Nginx, Apache, or Traefik configurations;
  • SSL certificates;
  • application configuration files;
  • custom scripts;
  • cron jobs;
  • backups.

 

If the infrastructure is stored alongside the source code - for example, in a Git repository - setting up a new server usually takes just a few minutes. This is precisely why the Infrastructure as Code approach has become so widespread in recent years, as it allows you to quickly reproduce a working environment on virtually any server.

Special attention should be paid to secrets and configuration. The .env file must not be stored in a public repository, but an up-to-date copy of it must be prepared before the migration begins.

Incidentally, the absence of .env is one of the most common reasons for a failed Docker Compose migration. Containers may start successfully, but the application will either run with errors or fail to start at all due to the absence of necessary environment variables.

 

 

 

 

You Don’t Need to Migrate the Containers

During the first migration, many people try to migrate the containers themselves. To do this, they use docker commit, export images, or even copy the entire /var/lib/dockerdirectory. At first glance, the idea seems logical, but this is not the right approach.

A container is a disposable component of the system. It is created from an image, launched, performs its task, and, if necessary, is recreated in a matter of seconds. That is the whole point of Docker. Therefore, you should not migrate the containers themselves, but rather everything that lies outside of them and needs to be preserved after a restart. Typically, this includes:

  • the application’s source code;
  • the docker-compose.yml file and other configurations;
  • Docker images (or access to the Registry from which they will be pulled);
  • Docker Volumes;
  • databases;
  • user files;
  • SSL certificates;
  • secrets and environment variables.

 

It is these - but not limited to these - data that are valuable. Containers can be recreated at any time if you have the image, configuration, and everything else the application needs to run.

 

 

 

 

What to Do with Docker Images

If a project uses images from Docker Hub, GitHub Container Registry, or its own registry, there are usually no complications. Simply download the necessary versions and start the containers.

docker compose pull
docker compose up -d

Docker Compose will automatically pull all the images specified in the configuration.

 

Things get more complicated if the project uses custom images that were built locally and haven’t been published anywhere. In that case, you have two options.

The first is to rebuild them on the new VPS:

docker compose build
docker compose up -d

 

The second is to save the finished image to an archive, transfer it to the new server, and import it there.

docker save my-image:latest -o my-image.tar

After copying the file, run:

docker load -i my-image.tar

 

If possible, it’s better to choose the first method, as it makes the migration process fully reproducible. This means you can deploy the project on another server at any time without having to transfer pre-built images or worry that a local build has been lost.

 

 

 

 

The Most Critical Step: Data Migration

During a Docker Compose migration, the primary focus should be on the data. Containers can always be recreated, but losing the contents of a database or Docker Volumes almost always becomes a serious problem, since most modern applications store their state there. Therefore, the migration must be performed with the utmost care.

If the project uses PostgreSQL, MySQL, MariaDB, or another DBMS, you should not copy the directory containing the database files while the database is still accepting queries. Even if everything seems to have gone smoothly, you may encounter corrupted tables or inconsistent data after restoration.

It’s safer to use the built-in backup tools.

For PostgreSQL, this is the standard pg_dump utility:

pg_dump -U postgres mydb > backup.sql

 

For MySQL, use mysqldump:

mysqldump -u root -p mydb > backup.sql

 

The resulting dump is transferred to the new VPS, after which the database is restored on the new server.

Yes, this method takes a little longer, but in return, you get a consistent backup and significantly reduce the risk of problems arising after the project goes live.

 

 

 

 

Migrating Docker Volumes

If the application stores data in Docker Volumes, those will also need to be migrated to the new server. This is where user files, downloaded content, cache, service data, and other information are often located - all of which must be preserved after migration.

First, review the list of existing volumes:

docker volume ls

 

One of the simplest ways to migrate them is to create an archive using a temporary container, for example:

docker run --rm \
-v app_data:/from \
-v $(pwd):/backup \
alpine tar czf /backup/app_data.tar.gz -C /from .

 

Simply copy the resulting archive to the new VPS server. Then create a new Docker volume and extract the saved data into it using the same method, with a temporary container.

This approach is considered much safer than attempting to copy Docker’s internal directories directly. Docker manages the data storage structure itself, so working with Volumes and archiving their contents helps avoid many issues when migrating a project.

 

 

 

 

Synchronizing User Files

Migrating user files is usually much simpler than migrating databases or Docker Volumes. Therefore, when dealing with images, documents, backups, or other uploadable data, it’s usually sufficient to use the rsync utility for incremental file synchronization.

For example:

rsync -avz /var/www/uploads/ user@new-server:/var/www/uploads/

 

The main advantage of rsync is that when run again, it transfers only new or modified files. This allows you to perform the initial synchronization in advance, while the old server is still running, and then run the command again immediately before switching over the project to transfer only the latest changes.

This is exactly how online stores, corporate portals, forums, CMS platforms, and other projects where users constantly upload new content are typically migrated. This approach helps reduce downtime to virtually zero.

 

 

 

 

How to Reduce Downtime to Virtually Zero

In most cases, there’s no need to completely shut down the project during migration. It’s much more convenient to first migrate the bulk of the data and then perform a brief final synchronization immediately before switching to the new VPS.

Typically, the process looks like this:

  1. The first synchronization of user files is performed using rsyncwhile the application continues to run;
  2. A backup of the database is created and transferred;
  3. Containers are launched on the new server, after which the application’s operation is verified;
  4. Maintenance mode is enabled on the old VPS, or writing new data is temporarily disabled;
  5. A resync is performed via rsync, which transfers only the changes that occurred after the command was first run;
  6. If necessary, the current state of the database is transferred or the latest changes are applied;
  7. DNS records are switched to the new server.

 

As a result, users may not even notice the migration. Typically, only operations involving data writing are unavailable, and only for a few seconds or minutes - it all depends on the volume of data and the specifics of the project itself.

One of the main advantages of Docker Compose is that the application can be fully deployed even before users start accessing the new server.

After migrating the data, simply run the following command:

docker compose up -d

 

If you’re using the latest images from the Registry, it’s recommended to update them first:

docker compose pull
docker compose up -d

 

After starting the application, make sure all services have started successfully:

docker ps

 

It’s also a good idea to check the container logs:

docker compose logs

or the log for a specific service:

docker compose logs nginx

 

It’s much easier to fix any errors found now than after users have been switched over.

 

 

 

 

Test the application before switching the DNS

Before changing the DNS records and migrating users to the new VPS, make sure the project is fully ready for production. It’s better to spend a few minutes testing now than to deal with errors after the migration is complete.

To start, open the application via a temporary domain, a local entry in the hosts file, or directly via the new server’s IP address. After that, check a few key points:

  • the application launches without errors;
  • all containers are in the Up state;
  • the database responds to requests;
  • user files are accessible;
  • authentication and the admin panel are working correctly;
  • SSL certificates are installed and in use;
  • Docker logs do not contain any errors.

If the project runs through a reverse proxy (Nginx, Traefik, or Caddy), make sure requests are routed correctly between all services.

After this check, you can update the DNS and switch users over to the new server.

 

 

 

Switch traffic and monitor the project’s performance

Once the new VPS has been fully tested, you can switch users over to it. Usually, all you need to do is change the domain’s A or AAAA record.

If you prepare in advance, the transition will go more smoothly. For example, 24 hours before the migration, you can reduce the TTL to 300 seconds; then, most clients will start accessing the new server within a few minutes after the DNS records are updated.

That said, you shouldn’t rely solely on the TTL. Some DNS servers operated by internet service providers and corporate networks cache records for longer than the specified time. For this reason, it’s best not to shut down the old VPS immediately after the switchover. It’s usually left running for a few more hours, or up to a day for large projects.

However, the work isn’t finished after changing the DNS. During the first few hours after migration, it’s advisable to closely monitor the new server’s status: CPU and memory usage, the disk subsystem, network activity, container logs, and the application itself. It is at this very moment that issues most often arise - issues that weren’t detected during testing.

A few standard commands come in handy for quick monitoring:

docker stats
docker compose logs -f
docker events

 

These will help you spot memory shortages, constant container restarts, application errors, and other issues in time - problems that are best resolved before users notice them.

 

 

 

Rollback Plan and the Most Common Migration Errors

Even if the migration was thoroughly prepared, it is, unfortunately, impossible to completely rule out the possibility of errors. Therefore, even before starting the migration, it’s worth planning a rollback scenario.

The simplest and most reliable option is not to shut down the old VPS immediately after launching the new one. While users are gradually transitioning to the new server, the old platform continues to operate, the data on it remains intact, and, if necessary, you can simply revert the DNS records to the old IP address. After that, you can calmly address any issues that have arisen and repeat the migration later.

This is precisely why experienced administrators are in no hurry to delete the old server. Sometimes a critical error is only detected several hours after the switchover, and the ability to quickly revert to the previous infrastructure helps avoid prolonged downtime.

Most often, problems arise not because of Docker at all. The cause may be common mistakes that are easy to make during the migration.

Mistake Consequence
.env file was not transferred The application fails to start or runs with incorrect configuration
SSL certificates were not copied The website becomes unavailable over HTTPS
Docker Volume paths have changed The application loses access to its data
Required firewall ports are closed Containers are running, but the service is inaccessible from outside
The database was copied while writes were still in progress Data corruption or data loss
DNS was switched before testing was completed Users begin encountering errors
Cron jobs were not migrated Backups, notifications, and scheduled tasks stop working
Directory permissions were not verified File and log write errors occur

 

If you don’t rush to switch users over and prepare a migration plan in advance, most of these problems can be avoided. That’s why preparation usually takes longer than the actual migration of Docker Compose to a new VPS.

 

 

 

 

What to Migrate and What Not to

So, let’s summarize and put everything together in one place. During a Docker Compose migration, not all of the server’s contents need to be transferred to the new VPS. Some components must be preserved, while others can be recreated by Docker without any issues.

Component Should be migrated
docker-compose.yml Yes
.env Yes
Docker Volumes Yes
Databases Yes
User files Yes
SSL certificates Yes
Docker Images If required
Containers No
Container cache No
Temporary files No

If you keep this rule in mind, the migration process itself becomes much clearer. The main goal of the entire migration is to preserve the application’s data, configuration, and environment. Docker can restore everything else on its own.

 

 

 

 

Automate Future Migrations

If you migrate Docker Compose regularly - for example, between test, staging, and production environments - it’s best to automate many routine operations over time. This reduces migration time and significantly lowers the likelihood of errors.

The following tools are most commonly used for such tasks:

  • Ansible - for configuring servers and automatically deploying Docker Compose;
  • GitHub Actions or GitLab CI/CD - for building images and automatic deployment;
  • rsync over SSH - for synchronizing user files;
  • Docker Registry - for storing your own Docker images;
  • Watchtower and similar tools - for automatically updating containers, if this approach is used in the infrastructure.

 

Even partial automation eliminates many repetitive tasks. And the less manual work involved during migration, the lower the likelihood of making a mistake at the worst possible moment.

 

 

 

 

FAQ

 

Do I need to migrate the Docker containers themselves?

No. Containers are considered disposable objects, and in most cases, it’s easier and better to recreate them using Docker Compose.

 

Can I just copy the /var/lib/dockerdirectory?

Technically, this is possible, but this method is by no means considered best practice. The directory contains Docker’s internal structure, which depends on the engine version, storage driver, and system configuration. It’s more reliable to migrate data using Docker Volumes, database backups, and recreating containers.

 

Do I need to migrate Docker images?

If the images are available on Docker Hub or your own registry, simply running docker compose pullis sufficient. Exporting them only makes sense when using locally built images or those that are not accessible from the outside.

 

How long does it take for DNS to update after switching servers?

If the TTL was reduced in advance, most users will switch to the new VPS within a few minutes. However, some DNS servers may cache records for longer, so it’s recommended to keep the old server running for a while longer.

 

Is it possible to completely avoid downtime?

In many cases, yes, it is possible. For example, if the application allows for a brief interruption in data writing, and the switchover is performed after preliminary file synchronization and testing of the new server, most users won’t even notice the migration.

 

What should be done with SSL certificates?

If you’re using self-signed certificates, they must be transferred along with the private keys. If you’re using Let’s Encrypt, you can either transfer the existing certificates or reissue them on the new server after the migration is complete.

 

 

 

Conclusion

So, we’ve established that migrating a project from Docker Compose to a new VPS server without downtime is entirely feasible. And this doesn’t require complex tools or non-standard solutions - all you need to do is organize the migration process correctly.

The main takeaway is simple: you shouldn’t migrate the containers themselves, but rather the infrastructure surrounding them. Configuration, databases, Docker Volumes, user files, certificates, environment variables, and other components essential for the application to function - these are what you should migrate, while the containers themselves can always be recreated if necessary.

If the new server is prepared in advance, all data is migrated securely, the application is fully tested before the DNS switch, and the old VPS remains available in case of a rollback, then for most users the migration will go virtually unnoticed. It is precisely this approach that allows you to migrate Docker Compose between servers without prolonged downtime or unnecessary risk.

3v-Hosting Team

Author

3v-Hosting Team

The 3v-Hosting Team is made up of a dedicated group of engineers and operators who are all about building and maintaining the backbone of our services. Every day, we dive into the world of virtual and dedicated servers, handling everything from deployment and monitoring to troubleshooting real-world issues that pop up in production environments. Most of our articles stem from hands-on experience rather than just theory. We share insights on the challenges we face: performance hiccups, configuration missteps, networking intricacies, and architectural choices that impact stability and reliability. Our mission is straightforward – we want to share knowledge that empowers you to manage your projects with fewer surprises and a lot more predictability.