Server Management

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 destination

The 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

OptionDescription
-aArchive mode, preserves permissions, timestamps, symlinks, owner
-vVerbose, show transferred files
-zCompress data during transfer
-PShow progress + resume partial transfers
--deleteDelete files at destination that no longer exist at source
--dry-run / -nSimulate without making changes
--excludeSkip files or directories matching a pattern
--bwlimit=KBLimit bandwidth (KB/s)
-e sshUse 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__/
.env

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>&1

Pull 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 --version

Rsync 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/24
echo "backupuser:StrongPassword" | sudo tee /etc/rsyncd.secrets
sudo chmod 600 /etc/rsyncd.secrets
sudo systemctl enable rsync
sudo systemctl start rsync

Connect from a client:

rsync -av /var/www/ backupuser@backup-server::backup/

On this page