Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

rsync: Efficient File Sync and Backup

By Kokil Thapa | Last reviewed: September 2026

rsync: Efficient File Sync and Backup is the first tool I reach for when a Laravel app, WordPress site, or legal-tech portal needs reliable file copies between servers. rsync sends only changed blocks over the wire, preserves permissions, and runs well over SSH on the Ubuntu boxes I maintain daily. If you handle Linux system administration for client sites, rsync belongs in your baseline toolkit alongside database dumps and off-site storage.

How does rsync work for efficient file sync and backup?

rsync is not a generic copy command. It builds a file list on both sides, compares size and modification time, and transfers only the bytes that differ. On a second run, a 2 GB upload directory might move 40 MB instead of the full tree.

That delta behaviour is why rsync scales on small VPS hosts common in Nepal. Bandwidth costs real money. A nightly sync that touches only changed Blade views, uploaded PDFs, or WooCommerce product images keeps backup windows short.

rsync runs in two common modes:

  • Push: the source server initiates the transfer to a remote destination.
  • Pull: the backup server connects inward and copies data from production.

For production, I prefer pull backups when possible. The backup host holds the SSH key. Production does not need outbound credentials to cold storage. That limits blast radius if the app server is compromised.

rsync Delta Transfer FlowSource Server/var/www/apprsync EngineCompare + deltaBackup Server/backups/hostFile listChanged blocksSSH tunnel encrypts rsync streamOnly deltas cross the network on repeat runs
rsync efficient file sync and backup: source listing, delta comparison, and encrypted transfer to backup storage

Local sync vs remote sync over SSH

A local rsync between disks on one machine is useful before major upgrades. Remote sync uses -e ssh implicitly when you specify user@host:/path.

# Local mirror — useful before Laravel or WordPress upgrades
rsync -aHAX --delete \
  /var/www/production/ \
  /mnt/snapshot/production-$(date +%F)/

# Remote pull from backup server (preferred pattern)
rsync -aHAX --delete --numeric-ids \
  -e "ssh -p 22 -i /root/.ssh/backup_pull_ed25519" \
  deploy@203.0.113.10:/var/www/current/ \
  /backups/sites/example.com/files/

Notice the trailing slash on the source path. /var/www/current/ copies the directory contents. Without the slash, rsync creates a nested current folder under the destination. That subtle difference has caused restore paths to drift on real deployments.

For deeper backup architecture, see Ubuntu server backup strategies and automated server backups complete setup.

What rsync flags should you use for production file backups?

Defaults are not enough for server backups. Production flags must preserve ownership, handle symlinks predictably, and delete stale files when you mirror a live tree.

Start with this baseline:

rsync -aHAX --delete --numeric-ids \
  --info=stats2,progress2 \
  --partial --partial-dir=.rsync-partial \
  -e "ssh -o BatchMode=yes -o ConnectTimeout=30" \
  SOURCE/ DEST/

Flag reference for daily operations

FlagPurposeProduction note
-aArchive mode: permissions, times, symlinksFoundation for almost every backup job
-HPreserve hard linksImportant for mail spools and some app caches
-APreserve ACLsNeeded when apps use fine-grained permissions
-XPreserve extended attributesRelevant for SELinux contexts on some hosts
--deleteRemove dest files absent on sourceTurns sync into a true mirror; test with dry-run first
--numeric-idsSkip UID/GID name mappingAvoids ownership shifts when user tables differ
--link-destHard-link unchanged filesEnables cheap daily snapshots on one disk
-zCompress during transferHelps over slow cross-border links; skip on LAN NVMe
--dry-runSimulate without writingRun before every new job or path change

The official rsync manual at rsync.samba.org documents edge cases for ACL and xattr support across filesystems. Always confirm your backup volume supports the attributes you preserve.

Mirror-only backups overwrite yesterday. Snapshot-style retention keeps multiple dated copies without duplicating unchanged files. Each run hard-links identical inodes from the previous snapshot.

BACKUP_ROOT="/backups/example.com/files"
TODAY=$(date +%Y-%m-%d)
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
DEST="${BACKUP_ROOT}/${TODAY}"
LINK="${BACKUP_ROOT}/${YESTERDAY}"

mkdir -p "${BACKUP_ROOT}"

rsync -aHAX --delete --numeric-ids \
  --link-dest="${LINK}" \
  -e "ssh -i /root/.ssh/backup_pull_ed25519" \
  deploy@203.0.113.10:/var/www/current/ \
  "${DEST}/"

On sister sites I maintain with Deployer 7 and GitLab CI, uploaded documents and shared storage paths sit outside the release symlink. Those paths belong in rsync jobs even when code deploys are zero-downtime. See how persistent storage fits into Notary Kathmandu deployment patterns and Adventure Third Pole Trek booking storage.

--link-dest Snapshot RetentionMon Snapshotfile Afile Bfile CTue Snapshotfile A linkedfile B newfile C linkedWed Snapshotfile A linkedfile B linkedfile C newUnchanged files share disk blocks via hard links
rsync --link-dest creates space-efficient daily snapshots for file sync and backup retention

How do you automate rsync file backups with cron on Linux?

Manual rsync works once. Production needs scheduled jobs, exit-code checks, logs, and alert hooks. I wrap rsync in a small shell script and call it from cron on Ubuntu 22/24 servers.

  1. Create a dedicated backup user or restrict root SSH keys to pull-only commands.
  2. Store scripts in /usr/local/bin/ with mode 750.
  3. Write logs to /var/log/backups/ with logrotate config.
  4. Run a --dry-run after any path or flag change.
  5. Monitor exit codes — rsync returns non-zero on partial transfer.

Example backup script with locking

#!/usr/bin/env bash
set -euo pipefail

LOCK="/var/lock/rsync-example.lock"
LOG="/var/log/backups/example-files.log"
SOURCE="deploy@203.0.113.10:/var/www/shared/storage/"
DEST="/backups/example.com/storage/"

exec 9>"${LOCK}"
flock -n 9 || { echo "Backup already running"; exit 1; }

{
  echo "=== $(date -Is) START ==="
  rsync -aHAX --delete --numeric-ids \
    --partial --partial-dir=.rsync-partial \
    -e "ssh -i /root/.ssh/backup_pull_ed25519 -o BatchMode=yes" \
    "${SOURCE}" "${DEST}"
  echo "=== $(date -Is) OK ==="
} >>"${LOG}" 2>&1

Install the cron entry as root on the backup server:

# /etc/cron.d/example-files-backup
30 2 * * * root /usr/local/bin/backup-example-files.sh

Pair file rsync with database dumps. A filesystem mirror without MySQL or PostgreSQL dumps gives you uploads but not orders, bookings, or client records. Read automate database backups on Linux and database backup strategies for small servers for the full picture.

For a focused walkthrough, see automate server backups with rsync and cron. When you need object storage, combine rsync with restic as described in offsite backups to S3 or R2 with rsync and restic.

Automated rsync Backup Pipelinecron 02:30Backup scriptflock + logProductionLocal snapshotslink-destOff-site copyS3 or R2Alert if exit code != 0
Cron-driven rsync efficient file sync and backup with local snapshots and optional off-site replication

How does rsync compare to scp, tar, and rclone for backups?

Teams often ask whether rsync is still the right choice in 2026. It depends on source, destination, and restore requirements. rsync excels at Unix-to-Unix incremental sync. It is weaker as a standalone encrypted archive format.

ToolBest forIncrementalTypical weakness
rsyncLinux server trees over SSHYes — delta blocksNo built-in encryption at rest
scpOne-off file copiesNoRe-copies full files every run
tar + gzipPortable archives, tape-style dumpsOnly with extra toolingFull archive rewrite unless scripted
rcloneS3, R2, Google Drive, multi-cloudYesMore moving parts than rsync-over-SSH

For a head-to-head on cloud targets, read rsync vs rclone for server backups. My usual pattern: rsync to a local or colocated backup VPS, then rclone or restic to object storage. That split keeps production SSH simple and puts encryption at the off-site layer.

Ubuntu documents rsync usage in the Ubuntu Server documentation. Debian’s rsync package notes are another solid reference for flag behaviour across versions.

When rsync is the wrong primary tool

Skip rsync as your only backup layer when you need immutable point-in-time recovery, cross-platform restores to Windows desktops, or compliance archives with WORM retention. Use rsync for fast sync, then layer restic, Borg, or cloud-native snapshots for long-term retention.

If you migrate hosts, rsync also helps pre-cutover sync. See website migration services for the broader cutover checklist beyond file copy alone.

What are common rsync mistakes that break production backups?

Most backup failures I troubleshoot are configuration issues, not rsync bugs. These patterns show up repeatedly on client servers and on my own Deployer-managed hosts.

Trailing slash and path drift

A missing or extra trailing slash changes the destination tree shape. Always test with --dry-run -i and inspect the first ten lines of planned changes. Document the exact source and dest paths in your runbook.

Running --delete before verifying the source

--delete mirrors deletions. If nginx points at the wrong root or a mount fails silently, rsync can propagate an empty directory and wipe the backup mirror. Use --delete-delay or verify mount points in a pre-flight check.

# Pre-flight: abort if source mount missing
if ! mountpoint -q /var/www/current; then
  echo "Source not mounted — aborting backup"
  exit 2
fi

Ignoring permissions and ownership

Restoring files without preserved UID, GID, and modes breaks Laravel storage/ writes and PHP-FPM uploads. Read Ubuntu file permissions explained and Linux file permissions and ACLs explained before stripping flags to “make it work”.

Backing up runtime noise

Exclude caches, sessions, and temporary upload chunks. They inflate transfer size and restore clutter.

# /etc/rsyncd.conf or --exclude-from file
/var/www/current/bootstrap/cache/*
/var/www/current/storage/framework/cache/*
/var/www/current/storage/framework/sessions/*
/var/www/current/storage/logs/*.log

Generate strong passphrases for encrypted off-site layers with a password generator and store secrets outside the repo. Never commit backup SSH keys to Git — a topic that overlaps with stopping Git from tracking file permissions.

rsync Backup Scope DecisionsNew backup job?Dry-run first--dry-run -iExclude cachesSmaller transfersDB dumps tooFiles alone faillink-dest snapshotsLocal retentionOff-site encryptrestic or rcloneTest restore quarterly — backups you never restore are guesses
Decision checklist for rsync efficient file sync and backup scope, exclusions, and off-site layers

Restore drills nobody schedules

A backup job that never gets restored is a guess. Quarterly, pick one random snapshot. Restore files to a temp path. Confirm a PDF opens, an image serves, and Laravel storage is writable by www-data. Log the drill date.

Ongoing monitoring fits under support and maintenance and domain registration and hosting when clients want hands-off ops. For JSON config exports from backup manifests, a JSON formatter helps validate automation output quickly.

Key Takeaways

  • Use rsync -aHAX --delete --numeric-ids for production mirrors, and always dry-run after path changes.
  • Prefer pull backups from a dedicated backup host with a restricted SSH key.
  • Add --link-dest for daily snapshots without multiplying disk use.
  • Pair file rsync with automated database dumps — files alone cannot restore transactional data.
  • Exclude caches and logs; verify mounts before any job that uses --delete.
  • Replicate local snapshots off-site with encryption via restic or rclone, then test restores quarterly.

People Also Ask

Is rsync still the best tool for Linux server backups in 2026?

Yes, for incremental file sync between Linux servers over SSH. rsync remains fast, widely packaged, and script-friendly on Ubuntu and Debian hosts. Pair it with encrypted off-site tooling when you need cloud retention or immutable archives.

Does rsync copy open or changing files safely?

rsync can miss changes to files that are actively written during the run. Quiesce apps or snapshot the filesystem first when consistency matters. Databases should be dumped with mysqldump or pg_dump, not copied live from data directories.

Space equals one full copy plus the sum of changed and new files across retained snapshots. Unchanged files share inodes via hard links. Retention policy and change rate determine growth, not the number of snapshot folders alone.

Can rsync backup Laravel storage and shared directories correctly?

Yes, when you include Deployer shared/ paths and preserve ownership with -aHAX --numeric-ids. Exclude storage/framework/cache and session temp dirs. Confirm www-data ownership after every test restore.

Build a backup stack you can restore from

rsync: Efficient File Sync and Backup earns its place because it is boring, fast, and inspectable. Delta sync keeps bandwidth costs down on Nepali and international links alike. Snapshot hard links give you history without buying new disks every month. The job is not done until database dumps, off-site copies, and restore drills sit beside the rsync cron entry.

If you want help wiring backups into a Laravel, WordPress, or legal-tech deployment pipeline, review the portfolio and reach out via contact us. I set up rsync jobs, retention, and monitoring on production Linux hosts regularly — so the next incident is a restore, not a rebuild.

Frequently Asked Questions

rsync compares file lists on source and destination, checks size and modification time, and transfers only the bytes that differ. A second run might move 40 MB from a 2 GB tree instead of the full copy.

Start with rsync -aHAX --delete --numeric-ids. Archive mode preserves permissions, times, and symlinks; -H keeps hard links; -A and -X cover ACLs and extended attributes. Add --partial and --partial-dir for interrupted transfers, and --info=stats2,progress2 for visibility. Use -e "ssh -o BatchMode=yes -o ConnectTimeout=30" for non-interactive remote jobs. Run --dry-run before every new path or flag change. Confirm your backup volume supports the attributes you preserve, because ACL and xattr behaviour varies across filesystems.

Push means the source server initiates the transfer to a remote destination. Pull means the backup server connects inward and copies data from production. For production, pull is preferred: the backup host holds the SSH key, and production does not need outbound credentials to cold storage. That limits blast radius if the app server is compromised. The article shows a pull example where the backup server runs rsync against deploy@host:/var/www/current/ using a dedicated ed25519 key.

A trailing slash on the source copies directory contents into the destination. Without it, rsync creates a nested folder under the destination, which shifts restore paths. The article notes this subtle difference has caused restore path drift on real deployments. Always test with --dry-run -i and inspect the first ten lines of planned changes. Document exact source and destination paths in your runbook so every operator gets the same tree shape during sync and restore.

Set BACKUP_ROOT, TODAY, and YESTERDAY dates, create today's destination folder, then run rsync with --link-dest pointing at yesterday's snapshot. Unchanged files share inodes via hard links, so you keep multiple dated copies without duplicating every byte. Mirror-only jobs overwrite yesterday; snapshot retention gives history on one disk. On Deployer-managed sites, include uploaded documents and shared storage paths outside the release symlink in these jobs, because zero-downtime code deploys do not copy persistent upload directories automatically.

Wrap rsync in a shell script with set -euo pipefail, flock locking to prevent overlapping runs, and logging to /var/log/backups/. Store scripts in /usr/local/bin/ with mode 750. Use a dedicated backup user or restrict root SSH keys to pull-only commands. Configure logrotate for log files. Example cron: 30 2 * root /usr/local/bin/backup-example-files.sh. Monitor exit codes because rsync returns non-zero on partial transfer. Run --dry-run after any path or flag change before relying on the scheduled job.

rsync excels at Unix-to-Unix incremental sync over SSH but has no built-in encryption at rest. scp suits one-off copies but re-transfers full files every run. tar plus gzip produces portable archives but rewrites full archives unless scripted carefully. rclone handles S3, R2, Google Drive, and multi-cloud targets with incremental support but adds more moving parts than rsync-over-SSH. A common pattern: rsync to a local or colocated backup VPS, then rclone or restic to object storage for encrypted off-site retention.

Yes, for incremental file sync between Linux servers over SSH. rsync remains fast, widely packaged, and script-friendly on Ubuntu and Debian hosts. Pair it with encrypted off-site tooling when you need cloud retention or immutable archives.

rsync can miss changes to files actively written during the run. Quiesce applications or snapshot the filesystem first when consistency matters. Databases should be dumped with mysqldump or pg_dump, not copied live from data directories. A filesystem mirror without MySQL or PostgreSQL dumps gives you uploads but not orders, bookings, or client records. Pair every file rsync job with automated database dumps so restores cover both static files and transactional data.

Space equals one full copy plus the sum of changed and new files across retained snapshots. Unchanged files share inodes via hard links. Retention policy and change rate determine growth, not the number of snapshot folders alone.

Trailing slash errors change destination tree shape. Running --delete before verifying the source can wipe a backup mirror if nginx points at the wrong root or a mount fails silently; use pre-flight mountpoint checks or --delete-delay. Stripping -aHAX flags breaks Laravel storage writes and PHP-FPM uploads on restore. Backing up runtime noise like bootstrap/cache, framework cache, sessions, and logs inflates transfers. Skipping restore drills means you never confirm a PDF opens, an image serves, or www-data can write to storage after recovery.

--delete removes destination files absent on the source, turning sync into a true mirror. That is correct for production mirrors using rsync -aHAX --delete --numeric-ids, but only after verification. If the source mount is missing or empty, --delete propagates that state and can erase your backup copy. Always dry-run first, confirm mount points in a pre-flight script, and consider --delete-delay until the job is proven stable. Never enable --delete on a new job without inspecting --dry-run -i output line by line.

Yes, when you include Deployer shared/ paths and preserve ownership with -aHAX --numeric-ids. Exclude storage/framework/cache and session temp dirs. Confirm www-data ownership after every test restore. Uploaded documents and shared storage sit outside the release symlink on Deployer 7 sites, so they belong in rsync jobs even when code deploys are zero-downtime. Without those paths, you restore application code but lose client uploads, booking attachments, or legal documents stored in persistent directories.

Skip rsync as your only backup layer when you need immutable point-in-time recovery, cross-platform restores to Windows desktops, or compliance archives with WORM retention. rsync is weaker as a standalone encrypted archive format. Use rsync for fast sync, then layer restic, Borg, or cloud-native snapshots for long-term retention. For host migrations, rsync still helps pre-cutover sync, but the broader cutover checklist includes DNS, SSL, database consistency, and application config beyond file copy alone.

Yes. File rsync alone cannot restore transactional data. Orders, bookings, client records, and application state live in MySQL or PostgreSQL, not only in uploaded files. Automate mysqldump or pg_dump on a schedule parallel to your rsync cron entry. Store dumps on the same backup host or replicate them off-site with the same restic or rclone layer used for file snapshots. A complete backup stack needs files, database dumps, off-site encrypted copies, and quarterly restore drills to a temp path.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: