Rsync Command Builder
Transfer Mode
Source (Local) → Destination (Remote)
Core Options
Sync Behavior
Backup
Filters
Performance & Logging
rsync -avzh --progress /path/to/source/ remote-host:/path/to/destination/
Common Recipes
What is rsync?
rsync is a fast, versatile file synchronization tool for Linux/Unix. It uses a delta-transfer algorithm that only sends the differences between source and destination files, making it extremely efficient for incremental backups and remote synchronization over SSH.
Common rsync Flags
| Flag | Description |
|---|---|
| -a | Archive mode (recursive + preserve permissions, times, symlinks, owner, group) |
| -v | Verbose — list files being transferred |
| -z | Compress data during transfer |
| --progress | Show progress for each file |
| --delete | Delete files on dest that don't exist on source |
| -n | Dry run — simulate without transferring |
| -e 'ssh -p 2222' | Specify SSH command with custom port/key |
| --exclude | Exclude files matching pattern |
Trailing Slash Matters
In rsync, the trailing slash on the source path has meaning:
rsync -a /src/dir/ /dest/— copies contents of dir into /dest/rsync -a /src/dir /dest/— copies the directory itself into /dest/dir/
Backup Strategies with rsync
rsync excels at incremental backups because it only transfers changed bytes. Common backup patterns:
- Mirror backup —
rsync -a --delete /src/ /backup/keeps an exact copy, removing files deleted from source - Incremental with hardlinks — Use
--link-destto create space-efficient snapshot-style backups where unchanged files are hardlinked to the previous backup - Remote backup over SSH —
rsync -azP -e 'ssh -p 22' /data/ user@backup:/data/compresses and resumes interrupted transfers
rsync vs scp
| Feature | rsync | scp |
|---|---|---|
| Delta transfer | Yes — only changed bytes | No — full file copy |
| Resume interrupted | Yes (--partial) | No |
| Exclude patterns | Yes (--exclude) | No |
| Preserve permissions | Yes (-a) | Yes (-p) |
| Best for | Recurring sync, large dirs | One-off small file transfers |
Snapshot Backups with --link-dest
The --link-dest flag is rsync's killer feature for backups. It creates space-efficient snapshots by hard-linking unchanged files to the previous backup. Each snapshot looks like a full backup but only uses disk space for files that actually changed:
#!/bin/bash
# Snapshot-style incremental backup (like Time Machine)
BACKUP_ROOT="/backups"
LATEST="$BACKUP_ROOT/latest"
TIMESTAMP=$(date +%Y-%m-%d_%H%M%S)
TARGET="$BACKUP_ROOT/$TIMESTAMP"
rsync -a --delete \
--link-dest="$LATEST" \
/data/ "$TARGET/"
# Update "latest" symlink
rm -f "$LATEST"
ln -s "$TARGET" "$LATEST"
# Result: each $TIMESTAMP dir is a full snapshot
# but only changed files use new disk space
# Typical savings: 95-99% vs full copies
# Clean up snapshots older than 30 days
find "$BACKUP_ROOT" -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +Deployment Patterns with rsync
rsync is widely used for deploying web applications. The atomic deploy pattern uses symlinks to ensure zero-downtime releases. For managing SSH connection settings used by rsync, see our SSH Config Generator.
# Atomic deploy with symlinks (zero-downtime) RELEASE=$(date +%Y%m%d%H%M%S) TARGET="/var/www/releases/$RELEASE" # 1. Sync build artifacts to new release directory rsync -azP --delete \ --exclude='.env' \ --exclude='node_modules' \ --exclude='storage' \ ./dist/ deploy@web:/var/www/releases/$RELEASE/ # 2. Run remote post-deploy commands ssh deploy@web " cd $TARGET && npm ci --production ln -sfn $TARGET /var/www/current # atomic symlink swap sudo systemctl reload nginx " # Simple deploy (non-atomic, good for static sites) rsync -azP --delete \ --exclude='.git' \ --exclude='.env' \ ./build/ deploy@web:/var/www/html/ # Deploy with pre-sync validation (dry run first) rsync -azn --delete ./dist/ deploy@web:/var/www/html/ && \ rsync -azP --delete ./dist/ deploy@web:/var/www/html/
Server Migration with rsync
Migrating data between servers is rsync's sweet spot. The pre-sync + final sync pattern minimizes downtime by transferring the bulk of data while the old server is still running:
# Phase 1: Pre-sync (while old server is live, takes hours for large data) rsync -azP --delete \ -e 'ssh -p 22' \ root@old-server:/var/lib/data/ \ /var/lib/data/ # Phase 2: Final sync (stop services, sync remaining changes, seconds) ssh root@old-server "systemctl stop myapp" rsync -azP --delete \ -e 'ssh -p 22' \ root@old-server:/var/lib/data/ \ /var/lib/data/ systemctl start myapp # For databases: use --checksum for integrity verification rsync -az --checksum --delete \ root@old-server:/var/lib/postgresql/ \ /var/lib/postgresql/
Troubleshooting Common rsync Errors
| Error | Cause | Fix |
|---|---|---|
| rsync: connection unexpectedly closed | SSH connection dropped, OOM on remote | Use --partial --progress to resume, check remote memory |
| Permission denied (13) | No read permission on source or write on dest | Use --no-perms --no-owner --no-group or run as root |
| rsync: failed to set times | Filesystem doesn't support timestamps (FAT32, NFS) | Add --no-times or use --modify-window=1 |
| sending incremental file list (then nothing) | Files are identical, nothing to transfer | Normal behavior — rsync only transfers differences |
| Argument list too long | Too many exclude patterns on command line | Use --exclude-from=file.txt instead of multiple --exclude |
| IO error encountered (23) | Some files vanished during transfer | Add --ignore-missing-args for transient files (logs, temp) |
Filter Rules: Include Before Exclude
When combining --include and --exclude, order matters. rsync processes filter rules top-to-bottom and uses the first match. To selectively sync specific files, always put includes before excludes:
# Correct: sync only .py files (include first, then exclude everything else) rsync -av --include='*.py' --exclude='*' /src/ /dest/ # Correct: sync .py and .txt, exclude rest rsync -av --include='*.py' --include='*.txt' --exclude='*' /src/ /dest/ # WRONG: this copies NOTHING — exclude fires first rsync -av --exclude='*' --include='*.py' /src/ /dest/ # Recursive include requires directory includes too: rsync -av --include='*/' --include='*.py' --exclude='*' /src/ /dest/ # The --include='*/' lets rsync descend into subdirectories
For complex filter rules, use --filter='merge .rsync-filter' to load rules from a file, keeping your command line clean and your filters version-controlled.
When NOT to Use Compression (-z)
The -z flag compresses data during transfer, which helps over slow WAN links. However, compression hurts performance in several common scenarios:
- Already-compressed files — JPEG, PNG, MP4, .gz, .zip, .zst — compression wastes CPU cycles with zero size reduction
- LAN transfers — gigabit or faster networks are bottlenecked by CPU, not bandwidth. Compression slows transfers by 30-50%
- Large binary files — database dumps, disk images, and compiled binaries compress poorly and add overhead
| Scenario | Use -z? | Why |
|---|---|---|
| Code/configs over WAN | Yes | Text compresses 60-80%, saves bandwidth |
| Logs over slow link | Yes | Log files compress extremely well |
| Media files (JPEG/MP4) | No | Already compressed, CPU overhead for 0% gain |
| LAN (1Gbps+) | No | CPU becomes the bottleneck, not network |
| Mixed content over WAN | Maybe | Use --skip-compress=gz/jpg/mp4/zip to skip pre-compressed |
Privacy: This tool runs entirely in your browser. No commands are executed — it only generates the command text for you to copy and run.