Docs / Migration Guides / Live Migration with rsync for Minimal Downtime

Live Migration with rsync for Minimal Downtime

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 379 views · 3 min read

The rsync Migration Strategy

Live migration with rsync uses a two-phase approach: an initial full sync while the source server is still active, followed by a brief final sync that captures only changes since the first sync. This reduces downtime from hours to seconds or minutes.

Phase 1: Initial Sync (No Downtime)

# First full sync while source server is live
rsync -avz --progress --delete \
    -e "ssh -i ~/.ssh/migrate_key" \
    --exclude="/proc" --exclude="/sys" --exclude="/dev" \
    --exclude="/tmp" --exclude="/run" --exclude="/mnt" \
    --exclude="/var/lock" --exclude="/var/run" \
    root@source-server:/var/www/ \
    /var/www/

# This can take hours for large sites but source remains live
# Users experience no downtime during this phase

Phase 2: Database Sync

# Set up database replication for continuous sync
# MySQL: configure replica on destination
# Or for simpler setups, note the initial sync time

# Export database
ssh root@source "mysqldump --single-transaction --all-databases" | \
    mysql -h localhost

Phase 3: Final Sync (Brief Downtime)

# 1. Put source site in maintenance mode
ssh root@source "touch /var/www/html/.maintenance"

# 2. Final database dump (captures changes since initial dump)
ssh root@source "mysqldump --single-transaction --all-databases" | \
    mysql -h localhost

# 3. Final rsync (only transfers changed files - very fast)
rsync -avz --delete \
    root@source-server:/var/www/ /var/www/

# 4. Update DNS to point to new server
# 5. Remove maintenance mode on new server

# Total downtime: typically 1-5 minutes

Automated Migration Script

#!/bin/bash
# /usr/local/bin/migrate-live.sh
SOURCE="root@source-ip"
DEST="/var/www"
SSH_KEY="~/.ssh/migrate_key"
RSYNC_OPTS="-avz --delete --progress"
SSH_CMD="ssh -i $SSH_KEY"

echo "=== Phase 1: Initial sync ==="
rsync $RSYNC_OPTS -e "$SSH_CMD" $SOURCE:/var/www/ $DEST/

echo "=== Phase 2: Database sync ==="
$SSH_CMD $SOURCE "mysqldump --single-transaction --all-databases" | mysql

echo "=== Phase 3: Final sync ==="
read -p "Enable maintenance mode on source? [y/N] " confirm
[ "$confirm" = "y" ] || exit 1

$SSH_CMD $SOURCE "touch /var/www/html/.maintenance"
sleep 5

rsync $RSYNC_OPTS -e "$SSH_CMD" $SOURCE:/var/www/ $DEST/
$SSH_CMD $SOURCE "mysqldump --single-transaction --all-databases" | mysql

echo "=== Migration complete ==="
echo "Update DNS and verify the new server"

rsync Options Explained

# Key flags for migration:
-a    # Archive mode (preserves permissions, timestamps, symlinks)
-v    # Verbose output
-z    # Compress during transfer (saves bandwidth)
--delete  # Remove files on dest that do not exist on source
--progress  # Show transfer progress
--partial   # Keep partially transferred files (resume on failure)
--bwlimit=50000  # Limit bandwidth to 50 MB/s
--checksum  # Use checksums instead of mod-time (slower but more accurate)

Best Practices

  • Run the initial sync multiple times before the final cutover to minimize delta
  • Use --checksum for the final sync to catch any discrepancies
  • Schedule the cutover during lowest traffic period
  • Keep the source server running for 48h as fallback
  • Lower DNS TTL well in advance of migration
  • Test the new server thoroughly before DNS cutover

Was this article helpful?