When migrating a website, you need to transfer thousands of files between servers. The choice of tool affects speed, security, and convenience — especially during repeated synchronizations.
Comparing Transfer Tools
| Tool | Speed | Security | Incremental | Requirements |
|---|---|---|---|---|
| rsync | High | High (SSH) | Yes (changes only) | SSH on both servers |
| SCP | Medium | High (SSH) | No | SSH on both servers |
| FTP/SFTP | Medium | Low/High | No | FTP client |
| tar + SSH pipe | High | High | No | tar, SSH |
rsync — The Best Choice for Migration
rsync transfers only the changed blocks of files, which makes it indispensable for the final sync before switching DNS:
# Sync the directory with the remote server
rsync -avz --progress /var/www/example.com/ root@new-server:/var/www/example.com/
# Flags:
# -a — archive mode (preserves permissions, timestamps, symlinks)
# -v — verbose output
# -z — compress during transfer
# --progress — show progress
# Exclude unnecessary directories
rsync -avz --exclude=".git" --exclude="node_modules" /var/www/example.com/ root@new-server:/var/www/example.com/
# Remove files on the target that are missing from the source
rsync -avz --delete /var/www/example.com/ root@new-server:/var/www/example.com/
SCP — Fast Archive Transfer
># Copy a file to the remote server
scp backup.tar.gz root@new-server:/tmp/
# Copy a directory recursively
scp -r /var/www/example.com root@new-server:/var/www/
# Copy a file from the remote server locally
scp root@old-server:/var/www/example.com/config.php ./
# Use a non-standard SSH port
scp -P 2222 backup.tar.gz root@new-server:/tmp/
tar + SSH pipe — Transfer Without Intermediate Files
# Transfer the directory directly without creating an archive on disk
tar -czf - /var/www/example.com/ | ssh root@new-server "tar -xzf - -C /var/www/"
# This is faster than: create an archive → scp → extract
SFTP (Secure FTP) via lftp
># Parallel upload via lftp (5 connections)
lftp -u username,password sftp://new-server <<'EOF'
mirror -P5 /var/www/example.com /var/www/example.com
quit
EOF
- Day 1: Initial rsync sync (all files, slow)
- Migration day: Final rsync --delete (changes only, fast — 1–5 minutes)
- Switch DNS
SSH Keys for Automation
># Create a key pair (no passphrase, for automation)
ssh-keygen -t ed25519 -C "migration-key" -f ~/.ssh/migration_key -N ""
# Add the public key to the new server
ssh-copy-id -i ~/.ssh/migration_key.pub root@new-server
# Use a specific key with rsync
rsync -avz -e "ssh -i ~/.ssh/migration_key" /var/www/example.com/ root@new-server:/var/www/example.com/
Common File Transfer Errors
| Error | Cause | Fix |
|---|---|---|
| rsync: command not found on the remote server | The rsync package isn't installed on the target server — having it on the client isn't enough | Install it on both sides: apt install rsync -y |
| Permission denied (publickey) | The SSH key hasn't been copied to the new server yet, or a different default key is being used | Add the key explicitly: ssh-copy-id -i ~/.ssh/migration_key.pub root@new-server |
| rsync error: some files/attrs were not transferred (code 23) | Missing permissions on some files, or broken symlinks pointing nowhere | Run with --dry-run -v first to see the specific problem files before the real transfer |
| scp: /var/www/example.com: No such file or directory | The target directory on the new server hasn't been created yet | Create it in advance: ssh root@new-server "mkdir -p /var/www/example.com" |
Which Tool to Pick by Scenario
| Scenario | Recommended tool |
|---|---|
| A one-time transfer of a single archive | SCP |
| Regular synchronization with repeated runs | rsync |
| Transfer with no intermediate file on disk, low free space | tar + SSH pipe |
| Many small files, parallel upload needed | lftp with the mirror -P flag |
When None of These Tools Fit
- A database is being migrated, not files — rsync and SCP copy the file system, and a database needs mysqldump or a physical DBMS backup instead
- The data volume is tens of terabytes — a direct network transfer would take days, so physically shipping a disk or direct replication to object storage makes more sense
- Migration between very different file systems (for example from Windows hosting) — permissions and attributes don't map one-to-one and need extra normalization
- The site keeps accepting user writes during the transfer — a write pause or a sync queue is needed, otherwise the last minutes of activity are lost
For regular, repeated synchronization between servers rather than a one-time move, see "rsync: Server Synchronization and Backups". If it's specifically WordPress being migrated, the full scenario including the database is covered in "Migrating WordPress to a VDS: A Step-by-Step Guide".
Verifying the Result
After the transfer, confirm the data is identical on both sides:
# The file count should match on the old and new server
find /var/www/example.com -type f | wc -l
ssh root@new-server "find /var/www/example.com -type f | wc -l"
# Total directory size on both sides
du -sh /var/www/example.com
ssh root@new-server "du -sh /var/www/example.com"
# Checksum of the key configuration file
md5sum /var/www/example.com/wp-config.php
ssh root@new-server "md5sum /var/www/example.com/wp-config.php"
The full post-migration verification checklist, including DNS and SSL, is in "Website Verification Checklist After Migration".