Does Rsync Support Bidirectional Synchronization Between Linux and Windows?


1 views

html

Rsync is fundamentally designed as a one-way synchronization tool by default. When you run a typical rsync command like:

rsync -avz /source/directory/ user@remote:/destination/directory/

It will only push changes from the source to the destination. The operation direction is determined by the command structure.

In your case where you've created a Windows copy of a Linux server, let's examine what happens when files change:

  • If you delete/modify files on your Windows laptop and run the same rsync command, it will not automatically reflect those changes back to the server
  • The original server files remain unchanged because rsync doesn't track two-way changes by default

To achieve true two-way synchronization, you need to implement one of these approaches:

1. Manual Two-Pass Sync

Run rsync twice with reversed directions:

# Sync from server to laptop
rsync -avz --delete user@remote:/server/path/ /local/path/

# Then sync from laptop to server
rsync -avz --delete /local/path/ user@remote:/server/path/

2. Using Unison File Synchronizer

For true bidirectional sync, consider using Unison:

unison /local/path ssh://user@remote//server/path

Be extremely careful with the --delete option in bidirectional scenarios:

# This will DELETE files on the target that don't exist in source
rsync -avz --delete /source/ user@remote:/destination/

In a two-way sync setup, accidental deletions can propagate both ways. Always test with --dry-run first:

rsync -avzn --delete /source/ user@remote:/destination/

For your web server backup scenario, here's a safer approach:

# Preserve server changes first
rsync -avz --backup --backup-dir=~/rsync_backups user@remote:/var/www/ /cygdrive/c/web_backup/

# Then push local changes
rsync -avz --exclude='*.bak' /cygdrive/c/web_backup/ user@remote:/var/www/

For critical systems, consider using Git instead:

# On server
cd /var/www
git init
git add .
git commit -m "Initial commit"

# On Windows
git clone ssh://user@remote/var/www/.git c:\web_backup
# Make changes and push back
git add .
git commit -m "Local changes"
git push origin master

Rsync is primarily designed as a one-way synchronization tool, where changes from the source are propagated to the destination. The default behavior is to make the destination an exact replica of the source. However, with proper configuration, you can achieve bidirectional synchronization through careful scripting.

When you run a basic rsync command like:

rsync -avz /source/directory/ user@remote:/destination/directory/

This will only sync changes from the source to the destination. If you delete a file on your local machine (destination) and run rsync again, it will not delete the file on the server (source).

To achieve true bidirectional synchronization, you need to run rsync twice - once in each direction. Here's a practical example:

#!/bin/bash
# Sync server changes to local
rsync -avz --delete user@remote:/server/path/ /local/path/

# Sync local changes to server
rsync -avz --delete /local/path/ user@remote:/server/path/

The --delete flag ensures that deletions are propagated. Be extremely careful with this flag as it can cause data loss if misused.

For true bidirectional sync, consider using Unison instead of rsync:

unison /local/path ssh://user@remote//server/path/

Unison is specifically designed for two-way synchronization and handles conflicts more elegantly than rsync.

When implementing bidirectional sync with rsync:

  • Always test with --dry-run first
  • Consider using --backup and --backup-dir options
  • Be aware of potential race conditions
  • Monitor for infinite sync loops

For your specific web server scenario, here's a safer approach:

#!/bin/bash
# First, pull changes from server
rsync -avz --dry-run --delete user@remote:/var/www/ /cygdrive/c/web_backup/
# Review changes, then run without --dry-run

# Then push local changes to server
rsync -avz --dry-run --delete /cygdrive/c/web_backup/ user@remote:/var/www/
# Review changes, then run without --dry-run