Skip to main content

rawops.dev

Skip to tool content

Rsync Command Builder

Transfer Mode

Source (Local) → Destination (Remote)

Core Options

Sync Behavior

Backup

Filters

Performance & Logging

Command Output
rsync-command.sh
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

FlagDescription
-aArchive mode (recursive + preserve permissions, times, symlinks, owner, group)
-vVerbose — list files being transferred
-zCompress data during transfer
--progressShow progress for each file
--deleteDelete files on dest that don't exist on source
-nDry run — simulate without transferring
-e 'ssh -p 2222'Specify SSH command with custom port/key
--excludeExclude 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-dest to 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

Featurersyncscp
Delta transferYes — only changed bytesNo — full file copy
Resume interruptedYes (--partial)No
Exclude patternsYes (--exclude)No
Preserve permissionsYes (-a)Yes (-p)
Best forRecurring sync, large dirsOne-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

ErrorCauseFix
rsync: connection unexpectedly closedSSH connection dropped, OOM on remoteUse --partial --progress to resume, check remote memory
Permission denied (13)No read permission on source or write on destUse --no-perms --no-owner --no-group or run as root
rsync: failed to set timesFilesystem 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 transferNormal behavior — rsync only transfers differences
Argument list too longToo many exclude patterns on command lineUse --exclude-from=file.txt instead of multiple --exclude
IO error encountered (23)Some files vanished during transferAdd --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
ScenarioUse -z?Why
Code/configs over WANYesText compresses 60-80%, saves bandwidth
Logs over slow linkYesLog files compress extremely well
Media files (JPEG/MP4)NoAlready compressed, CPU overhead for 0% gain
LAN (1Gbps+)NoCPU becomes the bottleneck, not network
Mixed content over WANMaybeUse --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.

Related Tools & Resources