DEV Community

GSVPS
GSVPS

Posted on • Originally published at gsvps.com

How to Migrate a Linux VPS with rsync and Keep Downtime Low

Moving a Linux VPS to a new server is usually less about one command and more about sequencing. If you copy files too early, your data goes stale. If you switch DNS too soon, users land on an incomplete system. If you try to clone everything at once, you can easily bring across temporary paths and host-specific settings that do not belong on the new machine.

This article is adapted from a GSVPS tutorial on Linux VPS migration. Original source:
https://www.gsvps.com/articles/linux-vps-ru-he-qian-yi-dao-xin-fu-wu-qi-2026-zui-xin-rsync-jiao-cheng-ji-hu-1-1-wu-sun-qian-yi-wang-zhan-docker-he-shu-ju

The practical goal is not "zero risk." It is a controlled migration with a short write-free window and a clear rollback path.

1. Start with an inventory, not with rsync

Before copying anything, write down what actually lives on the old server:

  • web roots such as /var/www
  • Nginx or Apache config
  • application env files and secrets
  • database engines and database names
  • Docker Compose files, bind mounts, and named volumes
  • cron jobs
  • SSL certificate paths
  • firewall rules and open ports

Also note what should not be copied blindly:

  • /proc, /sys, /dev, /run
  • temporary files
  • mounted backup disks
  • bootloader state
  • network interface settings tied to the old host

That distinction matters. A migration usually fails because someone copied "everything" without deciding what "everything" meant.

2. Prepare the new server first

The destination host should be reachable and basically ready before any final sync:

  • create the admin user you will keep using
  • add SSH keys
  • install the packages your stack needs
  • confirm time, hostname, and firewall rules
  • make sure the target disks are mounted where you expect

Useful early checks:

hostnamectl
ip addr
df -h
lsblk
systemctl --failed
Enter fullscreen mode Exit fullscreen mode

If the new server cannot pass basic health checks, do not start the migration yet.

3. Lower DNS TTL before the cutover

If a site or API is moving, lower DNS TTL well before the migration window. That gives you a faster switchover later and reduces the period where some users still hit the old host.

This does not eliminate downtime by itself. It only shortens propagation pain when the final change happens.

4. Use rsync for repeatable file transfer

For website files, application directories, and many bind-mounted workloads, rsync is still one of the most useful tools because you can run it more than once.

A common pattern is:

  1. run an initial sync while services are still live
  2. validate the new server
  3. stop write-heavy services briefly
  4. run one final sync
  5. switch traffic

Example for a web root:

sudo rsync -aHAXx --numeric-ids --delete --info=progress2 \
  /var/www/ user@NEW_SERVER:/var/www/
Enter fullscreen mode Exit fullscreen mode

Flags here matter:

  • -a preserves recursion, permissions, timestamps, and symlinks
  • -HAX helps preserve hard links, ACLs, and xattrs where relevant
  • -x keeps the copy on one filesystem
  • --numeric-ids avoids UID or GID name mismatches
  • --delete keeps the destination aligned with the source

Do not use --delete casually against the wrong path. Verify both source and destination before pressing Enter.

5. Treat databases separately from static files

If the application writes to MySQL, MariaDB, or PostgreSQL, file sync alone is not enough.

Typical export commands:

mysqldump --single-transaction --routines --triggers DB_NAME > db.sql
pg_dump -Fc DB_NAME > db.dump
Enter fullscreen mode Exit fullscreen mode

Those should be imported on the new server after the database service is prepared.

For busy applications, the cleanest cutover is usually:

  • enable maintenance mode or temporarily stop writes
  • take the final dump or replication-consistent copy
  • import on the new host
  • run the final file sync

That write-free window is where you win or lose data consistency.

6. For Docker, migrate config and data intentionally

If the workload runs under Docker Compose, copy the Compose files, env files, and persistent data paths deliberately rather than assuming the container image is the hard part.

A simple sequence is:

docker compose config
docker compose down
sudo rsync -aHAX --delete /srv/app/ user@NEW_SERVER:/srv/app/
Enter fullscreen mode Exit fullscreen mode

Then on the new server:

docker compose pull
docker compose up -d
docker compose ps
Enter fullscreen mode Exit fullscreen mode

If you use named volumes instead of bind mounts, inspect where the actual persistent data lives before moving anything.

7. Validate before DNS cutover

Before sending production traffic to the new host, verify:

  • the web server starts cleanly
  • the application can connect to its database
  • file permissions are correct
  • scheduled jobs exist where needed
  • TLS certificates are present or can be reissued
  • uploads, login flows, and API writes still work

Useful checks include:

nginx -t
systemctl status nginx
docker compose logs --tail=100
ss -tlnp
curl -I http://127.0.0.1
Enter fullscreen mode Exit fullscreen mode

If the service stack is not healthy locally, changing DNS only hides the real problem behind a network symptom.

8. Keep rollback simple

Do not tear down the old server immediately after cutover.

Keep it available long enough to:

  • compare logs
  • recover missed files
  • re-check database state
  • reverse DNS if a critical issue appears

A migration plan is better when rollback is boring.

Final takeaway

The original GSVPS article focuses on using rsync to move a Linux VPS with minimal disruption. That is a sensible base, but the real success condition is broader: prepare the target host, separate static files from live data, run repeatable syncs, and keep the final write window short and explicit.

If you treat migration as a sequence instead of a copy job, rsync becomes a reliable part of the process rather than a gamble.

Top comments (0)