rsync synchronizes files between locations — local to local, local to remote, remote to local. It’s smart: it only transfers what’s changed, making it fast for incremental backups and deployments.

Basic Syntax

1
rsync [options] source destination

Local Sync

1
2
3
4
5
6
7
8
9
# Copy directory
rsync -av /source/dir/ /dest/dir/

# Copy directory (trailing slash matters!)
rsync -av /source/dir /dest/    # Creates /dest/dir/
rsync -av /source/dir/ /dest/   # Contents into /dest/

# Dry run (show what would happen)
rsync -avn /source/ /dest/

Remote Sync (SSH)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Local to remote
rsync -av /local/dir/ user@remote:/remote/dir/

# Remote to local
rsync -av user@remote:/remote/dir/ /local/dir/

# Different SSH port
rsync -av -e 'ssh -p 2222' /local/ user@remote:/remote/

# With SSH key
rsync -av -e 'ssh -i ~/.ssh/mykey' /local/ user@remote:/remote/

Common Options

1
2
3
4
5
6
7
8
9
-a, --archive     Archive mode (preserves permissions, timestamps, etc.)
-v, --verbose     Verbose output
-n, --dry-run     Show what would be transferred
-z, --compress    Compress during transfer
-P                Progress + partial (resume interrupted transfers)
--progress        Show progress
--delete          Delete files in dest not in source
-r, --recursive   Recurse into directories
-h, --human-readable  Human-readable sizes

Archive Mode (-a)

-a is equivalent to -rlptgoD:

1
2
3
4
5
6
7
-r  Recursive
-l  Copy symlinks as symlinks
-p  Preserve permissions
-t  Preserve modification times
-g  Preserve group
-o  Preserve owner
-D  Preserve device files and special files

Exclusions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Exclude pattern
rsync -av --exclude='*.log' /source/ /dest/

# Multiple exclusions
rsync -av --exclude='*.log' --exclude='tmp/' /source/ /dest/

# Exclude from file
rsync -av --exclude-from='exclude.txt' /source/ /dest/

# Include/exclude combinations
rsync -av --include='*.py' --exclude='*' /source/ /dest/

exclude.txt example

n...og_ltdipometygp_/cmaocdhuel_e_s//

Delete Options

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Delete files in dest not in source
rsync -av --delete /source/ /dest/

# Delete before transfer (frees space first)
rsync -av --delete-before /source/ /dest/

# Delete after transfer
rsync -av --delete-after /source/ /dest/

# Delete excluded files from dest
rsync -av --delete-excluded --exclude='*.log' /source/ /dest/

Progress and Stats

1
2
3
4
5
6
7
8
# Show progress per file
rsync -av --progress /source/ /dest/

# Overall progress (rsync 3.1+)
rsync -av --info=progress2 /source/ /dest/

# Show stats at end
rsync -av --stats /source/ /dest/

Bandwidth Limiting

1
2
3
4
5
# Limit to 1 MB/s
rsync -av --bwlimit=1000 /source/ /dest/

# Limit to 500 KB/s
rsync -av --bwlimit=500 /source/ /dest/

Practical Examples

Simple Backup

1
rsync -av --delete /home/user/ /backup/user/

Backup with Exclusions

1
2
3
4
5
rsync -av --delete \
    --exclude='.cache/' \
    --exclude='Downloads/' \
    --exclude='*.tmp' \
    /home/user/ /backup/user/

Deploy Website

1
2
3
4
rsync -avz --delete \
    --exclude='.git' \
    --exclude='node_modules' \
    ./dist/ user@server:/var/www/site/

Mirror Directory

1
2
rsync -av --delete --backup --backup-dir=/backup/old \
    /source/ /dest/

Incremental Backup with Date

1
2
3
4
DATE=$(date +%Y-%m-%d)
rsync -av --link-dest=/backup/latest \
    /source/ /backup/$DATE/
ln -nsf /backup/$DATE /backup/latest

Resume Interrupted Transfer

1
2
rsync -avP user@remote:/large/file.tar.gz ./
# If interrupted, run same command to resume

Sync Only Certain Files

1
2
3
4
5
# Only .py files
rsync -av --include='*/' --include='*.py' --exclude='*' /source/ /dest/

# Only files modified in last 24h
find /source -mtime -1 -type f | rsync -av --files-from=- / /dest/

Checksum Mode

1
2
3
4
5
# Compare by checksum instead of time/size
rsync -avc /source/ /dest/

# Skip based on checksum
rsync -av --checksum /source/ /dest/

Handling Large Files

1
2
3
4
5
6
7
8
# Partial transfers + progress
rsync -avP /source/large.iso /dest/

# Compress (good for text, bad for already compressed)
rsync -avz /source/ /dest/

# Skip compress for certain extensions
rsync -avz --skip-compress=gz/jpg/mp4/zip /source/ /dest/

Permissions and Ownership

1
2
3
4
5
6
7
8
# Preserve everything
rsync -av /source/ /dest/

# Don't preserve owner (useful when not root)
rsync -av --no-owner --no-group /source/ /dest/

# Set specific permissions
rsync -av --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r /source/ /dest/

Over SSH with Sudo

1
2
# Remote rsync with sudo
rsync -av --rsync-path="sudo rsync" /local/ user@remote:/dest/

Cron Backup Script

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash
# backup.sh

SOURCE="/home/user/"
DEST="/backup/user"
LOG="/var/log/backup.log"

rsync -av --delete \
    --exclude='.cache' \
    --exclude='Downloads' \
    "$SOURCE" "$DEST" >> "$LOG" 2>&1

echo "Backup completed: $(date)" >> "$LOG"
1
2
# Crontab
0 2 * * * /path/to/backup.sh

Comparison: rsync vs cp vs scp

Featurersynccpscp
Delta transfer
Resume
Progress
Remote
Compress
Delete

Troubleshooting

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Very verbose (debug)
rsync -avvv /source/ /dest/

# Show what would transfer
rsync -avn /source/ /dest/

# Test SSH connection
ssh user@remote 'rsync --version'

# Check remote path
rsync -avn user@remote:/path/to/check/ ./test/

Quick Reference

OptionPurpose
-aArchive mode
-vVerbose
-zCompress
-PProgress + partial
-nDry run
--deleteRemove extraneous files
--excludeSkip files matching pattern
--bwlimitBandwidth limit
-e sshUse SSH (default)

rsync is the backbone of backups and deployments. Learn the archive flag (-a), understand the trailing slash behavior, and always dry-run (-n) destructive operations first. Once you’re comfortable, you’ll use it for everything from syncing config files to mirroring terabytes.