Rsync File Sync & Backup
Use rsync to sync files between servers, create incremental backups, and automate transfers over SSH
Rsync is the standard tool for efficient file transfer and synchronization on Linux. It only transfers changed parts of files (delta transfer), works over SSH, and supports incremental backups with hard links.
Basic syntax
rsync [options] source destinationThe trailing slash on source matters:
# Copy contents of dir/ into /backup/dir/
rsync -av /var/www/dir/ /backup/dir/
# Copy dir/ itself into /backup/ (creates /backup/dir/)
rsync -av /var/www/dir /backup/Common options
| Option | Description |
|---|---|
-a | Archive mode, preserves permissions, timestamps, symlinks, owner |
-v | Verbose, show transferred files |
-z | Compress data during transfer |
-P | Show progress + resume partial transfers |
--delete | Delete files at destination that no longer exist at source |
--dry-run / -n | Simulate without making changes |
--exclude | Skip files or directories matching a pattern |
--bwlimit=KB | Limit bandwidth (KB/s) |
-e ssh | Use SSH as transport |
Sync to another server via SSH
rsync -avz -e ssh /var/www/mysite/ user@remote-server:/var/www/mysite/With a non-standard SSH port:
rsync -avz -e "ssh -p 2222" /var/www/mysite/ user@remote-server:/var/www/mysite/With SSH key:
rsync -avz -e "ssh -i ~/.ssh/backup_key" /var/www/ user@remote-server:/backup/www/Mirror a directory (with deletion)
Exact copy, files deleted at source are also deleted at destination:
rsync -av --delete /var/www/mysite/ user@remote:/var/www/mysite/--delete removes files at the destination. Always run with --dry-run first to preview changes before executing.
Exclude files and directories
# Exclude a specific directory
rsync -av --exclude='node_modules/' /var/www/myapp/ user@remote:/var/www/myapp/
# Exclude multiple patterns
rsync -av \
--exclude='*.log' \
--exclude='.git/' \
--exclude='node_modules/' \
--exclude='*.tmp' \
/var/www/myapp/ user@remote:/var/www/myapp/
# Use an exclude file
rsync -av --exclude-from='/etc/rsync-exclude.txt' /var/www/ /backup/www/Example /etc/rsync-exclude.txt:
*.log
*.tmp
.git/
node_modules/
__pycache__/
.envIncremental backups with hard links
This technique creates daily snapshots where unchanged files are hard-linked (no extra disk space), and only changed files are new copies:
#!/bin/bash
BACKUP_DIR="/backup/mysite"
SOURCE="/var/www/mysite/"
DATE=$(date +%Y-%m-%d)
LATEST="$BACKUP_DIR/latest"
mkdir -p "$BACKUP_DIR/$DATE"
rsync -av --delete \
--link-dest="$LATEST" \
"$SOURCE" \
"$BACKUP_DIR/$DATE/"
# Update the symlink to the latest backup
ln -snf "$BACKUP_DIR/$DATE" "$LATEST"
echo "Backup completed: $BACKUP_DIR/$DATE"Each day creates a full-looking snapshot in /backup/mysite/2025-01-15/, but only new/changed files use extra disk space.
Automate with cron
sudo nano /etc/cron.d/rsync-backup# Daily backup at 2 AM
0 2 * * * root rsync -az --delete /var/www/ user@backup-server:/backup/www/ >> /var/log/rsync-backup.log 2>&1Pull files from remote server
Rsync can also pull (download) from a remote source:
# Download from remote to local
rsync -avz user@remote-server:/var/www/mysite/ /local/restore/
# Download database backup from remote
rsync -avz user@remote:/backup/db-latest.sql.gz /tmp/Bandwidth limiting
Useful when syncing large files on a production server without saturating the network:
# Limit to 5 MB/s
rsync -avz --bwlimit=5120 /var/www/ user@remote:/backup/www/Monitor rsync progress
# Show progress per file
rsync -av --progress /large/dataset/ user@remote:/backup/
# Show overall transfer stats
rsync -av --stats /var/www/ user@remote:/backup/www/Useful one-liners
# Sync local directory to S3-compatible storage via rclone (alternative)
# See: rclone sync /var/www/ remote:bucket/www/
# Test what would be transferred (dry run)
rsync -avn --delete /var/www/mysite/ user@remote:/var/www/mysite/
# Sync only files newer than 7 days
find /var/www/ -mtime -7 | rsync -av --files-from=- / user@remote:/backup/recent/
# Check rsync version
rsync --versionRsync daemon (without SSH)
For LAN backups or when SSH is not available, run rsync as a daemon:
sudo nano /etc/rsyncd.conf[backup]
path = /backup
comment = Backup storage
read only = no
auth users = backupuser
secrets file = /etc/rsyncd.secrets
hosts allow = 10.0.0.0/24echo "backupuser:StrongPassword" | sudo tee /etc/rsyncd.secrets
sudo chmod 600 /etc/rsyncd.secrets
sudo systemctl enable rsync
sudo systemctl start rsyncConnect from a client:
rsync -av /var/www/ backupuser@backup-server::backup/Systemd Timer: Modern Alternative to Cron
Use systemd timers to schedule periodic tasks. More reliable than cron: integrated logs, dependencies, error handling and automatic retries.
SSH Bastion / Jump Host
Set up an SSH bastion (jump host) to securely access private servers through a single public entry point