How to Use Rsync Over SSH for Automated Server-to-Server Backups and Sync

Quick Technical Answer:

To synchronize files securely between two Linux VPS servers over SSH, use the standard command: rsync -avzP -e "ssh -p 22" /local/source/ user@remote_ip:/remote/destination/. The flags -a preserves permissions and timestamps, -v enables verbose output, -z enables gzip transmission compression, and -P preserves partial transfers with a live progress bar. To make it automated, use passwordless Ed25519 SSH keys and schedule it inside crontab.

Why Rsync Remains the King of Linux Backup & Migration Utilities

When moving large datasets—such as multi-gigabyte WordPress media uploads, database dumps, and application assets—between cloud servers, traditional tools like FTP, SCP, or raw tar archives transfer every single byte sequentially. If a 10GB transfer is interrupted at 99%, standard SCP forces you to re-upload the entire file from scratch.

Rsync (Remote Sync) revolutionized data synchronization by introducing the rolling checksum delta-transfer algorithm. Rsync compares the source and destination directories, identifies which blocks of a file have changed, and transfers only the differential byte changes. If a 5GB database backup file only has 50MB of new entries, rsync transmits only that 50MB delta—slashing transfer times and bandwidth bills by over 95%.

Tunneling rsync through an encrypted SSH connection provides end-to-end cryptographic protection, ensuring credentials and proprietary web assets cannot be intercepted in transit.

Step 1: Anatomy of Essential Rsync Flags

Understanding rsync flags prevents catastrophic data loss errors (such as accidentally wiping destination files):

Flag Full Parameter Operational Function
-a --archive Archive mode; preserves file permissions, ownership, symlinks, timestamps, and recursively traverses subdirectories.
-v --verbose Provides detailed console output listing each file being transferred.
-z --compress Compresses data in flight using zlib to minimize network bandwidth consumption.
-P --partial --progress Shows a live progress bar and preserves partially transferred files so interrupted jobs resume without restart.
--delete Mirror deletion Deletes files on the remote destination if they no longer exist on the source, creating an exact mirror.

Step 2: The Critical Trailing Slash Rule

WARNING: The Trailing Slash Changes Behavior Completely!

rsync -a /source/folder /dest/ creates /dest/folder/file.txt (copies the folder itself).
rsync -a /source/folder/ /dest/ creates /dest/file.txt (copies only the contents of the folder).

Step 3: Setting Up Passwordless SSH Keys for Automation

To run rsync inside automated cron scripts, the source server must authenticate to the remote destination server without password prompts using high-security Ed25519 SSH keys:

# Generate a dedicated backup keypair on the SOURCE server (no passphrase)
ssh-keygen -t ed25519 -f ~/.ssh/backup_key -N ""

# Copy the public key to the REMOTE destination server
ssh-copy-id -i ~/.ssh/backup_key.pub -p 22 backupuser@remote_backup_ip

# Test SSH connection without password
ssh -i ~/.ssh/backup_key -p 22 backupuser@remote_backup_ip "echo SSH Connection Successful"

Step 4: Real-World Synchronizations with Non-Standard Ports & Exclusions

If your remote backup server uses a hardened custom SSH port (e.g. port 2222) and you want to exclude cache and temp files:

# Rsync with custom SSH port and exclude filters
rsync -avzP --delete   -e "ssh -i /root/.ssh/backup_key -p 2222"   --exclude="wp-content/cache/*"   --exclude="*.tmp"   --exclude="node_modules"   --bwlimit=10000   /var/www/html/   backupuser@remote_backup_ip:/backups/live_site/

Note: --bwlimit=10000 caps transfer speeds at 10 MB/s, preventing rsync from saturating server bandwidth during business hours.

Step 5: Automated Nightly Backup Script with Crontab

Create a production bash backup script that logs all execution output:

sudo nano /usr/local/bin/nightly-sync.sh

Insert the following automated script:

#!/bin/bash
set -e

TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
LOG_FILE="/var/log/rsync-backup.log"

echo "[${TIMESTAMP}] Starting Rsync Backup..." >> "$LOG_FILE"

rsync -aqz --delete   -e "ssh -i /root/.ssh/backup_key -p 22"   --exclude="*.log"   --exclude="cache/*"   /var/www/html/   backupuser@remote_backup_ip:/backups/current/ >> "$LOG_FILE" 2>&1

echo "[$(date +"%Y-%m-%d_%H-%M-%S")] Backup Completed Successfully." >> "$LOG_FILE"

Make the script executable and schedule it in crontab:

# Grant execution permissions
sudo chmod +x /usr/local/bin/nightly-sync.sh

# Edit system crontab
sudo crontab -e

# Run every night at 2:30 AM
30 2 * * * /usr/local/bin/nightly-sync.sh

Frequently Asked Questions (FAQ)

How do I perform a safe dry run before running rsync with –delete?

Always add the -n or --dry-run flag: rsync -avzPn --delete .... Rsync will print exact logs of which files would be transferred or deleted without touching the actual disks.

Can rsync preserve extended attributes and ACLs?

Yes. Add -A (preserve Access Control Lists) and -X (preserve extended attributes/SELinux contexts) to your rsync command flags.

Advanced Rsync Performance Tuning: SSH Cipher Selection & 10Gbps Links

When synchronizing vast datasets across modern 1Gbps or 10Gbps high-bandwidth VPS networks, the default SSH encryption cipher (frequently AES-256-CTR) can bottleneck on CPU cryptographic throughput. In tests across modern multi-core Linux servers, switching the transport cipher to chacha20-poly1305 or aes128-gcm increases transfer throughput by up to 45% while decreasing server CPU overhead:

# High-throughput rsync utilizing hardware-accelerated ChaCha20 cipher
rsync -avzP -e "ssh -c [email protected] -i /root/.ssh/backup_key -p 22" \
  --numeric-ids \
  --inplace \
  /var/www/html/ backupuser@remote_backup_ip:/backups/current/

The --inplace flag instructs rsync to update the destination file directly instead of writing a temporary file and moving it into place, substantially reducing disk write wear and temporary file IO overhead during massive database file syncs.

Troubleshooting Common Rsync Exit Error Codes

Exit Code Error Description Root Cause & Diagnostic Solution
Code 12 Error in rsync protocol data stream SSH connection dropped unexpectedly or remote rsync binary is missing on target server. Install rsync on destination.
Code 23 Partial transfer due to error Permission denied on specific destination files. Verify destination directory ownership with chown -R backupuser:backupuser.
Code 24 Partial transfer due to vanished source files Log or cache files were deleted by an active daemon during transfer. Add --exclude="*.log" to suppress warnings.

Build Disaster-Resilient Backups on CpanelFree

Connect multiple cloud locations with unmetered private networking and pure NVMe performance on CpanelFree Cloud VPS.

Deploy Your Backup Cloud Node →

Leave a Comment