
How to Copy Files with rsync over SSH
Remote file synchronization is a critical skill for anyone managing servers or working with distributed systems. The rsync tool over SSH provides a secure, efficient, and flexible way to copy files between systems while preserving permissions, timestamps, and only transferring changed data. This guide will walk you through everything from basic rsync syntax to advanced scenarios, troubleshooting common issues, and optimizing performance for production environments.
How rsync over SSH Works
Rsync combines the power of remote synchronization with SSH’s security layer. Unlike simple file copy commands, rsync uses a sophisticated algorithm that compares source and destination files, transferring only the differences. When tunneled through SSH, all data transmission is encrypted and authenticated.
The process works by establishing an SSH connection to the remote host, then spawning an rsync process on both ends. These processes communicate through the encrypted tunnel, exchanging checksums and file metadata before transferring actual data. This approach makes rsync incredibly efficient for incremental backups and large file transfers.
Basic rsync Syntax and Setup
Before diving into examples, ensure both systems have rsync installed. Most Linux distributions include it by default, but you can install it using your package manager:
# Ubuntu/Debian
sudo apt-get install rsync
# CentOS/RHEL
sudo yum install rsync
# macOS
brew install rsync
The basic syntax for rsync over SSH follows this pattern:
rsync [options] source user@host:destination
Here’s a simple example copying a local directory to a remote server:
rsync -avz /local/path/ user@remote-server:/remote/path/
The most commonly used options are:
- -a: Archive mode (preserves permissions, timestamps, symbolic links)
- -v: Verbose output
- -z: Compress data during transfer
- -P: Show progress and keep partially transferred files
- –delete: Delete files in destination that don’t exist in source
Step-by-Step Implementation Guide
Setting Up SSH Keys (Recommended)
For automated transfers and better security, configure SSH key authentication:
# Generate SSH key pair
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# Copy public key to remote server
ssh-copy-id user@remote-server
# Test SSH connection
ssh user@remote-server
Basic File Transfer Examples
Copy a single file to remote server:
rsync -avz /path/to/file.txt user@remote-server:/destination/
Copy directory contents (note the trailing slash):
rsync -avz /source/directory/ user@remote-server:/destination/directory/
Copy directory itself (no trailing slash):
rsync -avz /source/directory user@remote-server:/destination/
Pull files from remote to local:
rsync -avz user@remote-server:/remote/path/ /local/destination/
Advanced Options and Configurations
For production environments, you’ll often need more sophisticated options:
# Exclude specific files or patterns
rsync -avz --exclude='*.log' --exclude='cache/' /source/ user@remote:/dest/
# Use specific SSH port
rsync -avz -e "ssh -p 2222" /source/ user@remote:/dest/
# Bandwidth limiting (KB/s)
rsync -avz --bwlimit=1000 /source/ user@remote:/dest/
# Dry run to see what would be transferred
rsync -avzn /source/ user@remote:/dest/
Real-World Use Cases and Examples
Website Deployment
Deploy a website while excluding development files:
rsync -avz --delete \
--exclude='.git/' \
--exclude='node_modules/' \
--exclude='*.log' \
/local/website/ user@webserver:/var/www/html/
Database Backup Synchronization
Sync database backups to a remote backup server:
#!/bin/bash
# backup-sync.sh
BACKUP_DIR="/var/backups/mysql"
REMOTE_HOST="backup-server.example.com"
REMOTE_USER="backup"
REMOTE_PATH="/backups/mysql-primary"
rsync -avz --delete \
--exclude='*.tmp' \
"$BACKUP_DIR/" \
"$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/"
if [ $? -eq 0 ]; then
echo "Backup sync completed successfully"
else
echo "Backup sync failed" >&2
exit 1
fi
Development Environment Synchronization
Keep development and staging environments in sync:
rsync -avz --delete \
--exclude='wp-config.php' \
--exclude='wp-content/uploads/' \
/var/www/development/ \
staging@staging-server:/var/www/staging/
Performance Optimization and Best Practices
Compression and Network Optimization
The effectiveness of compression depends on your data type and network speed:
Data Type | Compression Benefit | Recommended Option |
---|---|---|
Text files, code | High (60-80% reduction) | -z or –compress-level=6 |
Already compressed (videos, images) | Minimal (may slow transfer) | No compression |
Mixed content | Moderate (30-50% reduction) | -z with selective exclusion |
For high-bandwidth connections, disable compression for better CPU utilization:
rsync -av --no-compress /source/ user@remote:/dest/
SSH Connection Optimization
Configure SSH for better rsync performance in ~/.ssh/config:
Host production-server
HostName prod.example.com
User deploy
Port 22
IdentityFile ~/.ssh/deploy_key
Compression yes
ControlMaster auto
ControlPath ~/.ssh/control-%h-%p-%r
ControlPersist 600
This configuration enables SSH connection multiplexing, reusing existing connections for multiple rsync operations.
Troubleshooting Common Issues
Permission Denied Errors
When encountering permission issues:
# Check SSH connectivity first
ssh -v user@remote-server
# Verify destination directory permissions
ssh user@remote-server 'ls -la /destination/path/'
# Use sudo on remote side if needed
rsync -avz /source/ user@remote:/tmp/staging/
ssh user@remote 'sudo mv /tmp/staging/* /final/destination/'
Network Interruption Recovery
For unreliable connections, use the partial transfer and retry options:
rsync -avzP --timeout=60 --contimeout=60 /source/ user@remote:/dest/
Create a retry script for critical transfers:
#!/bin/bash
MAX_RETRIES=3
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
rsync -avzP /source/ user@remote:/dest/
if [ $? -eq 0 ]; then
echo "Transfer completed successfully"
exit 0
else
RETRY_COUNT=$((RETRY_COUNT + 1))
echo "Transfer failed, retry $RETRY_COUNT of $MAX_RETRIES"
sleep 10
fi
done
echo "Transfer failed after $MAX_RETRIES attempts" >&2
exit 1
Performance Issues
If transfers are slower than expected:
- Test network bandwidth:
iperf3 -c remote-server
- Monitor disk I/O:
iostat -x 1
- Check CPU usage during compression
- Use
rsync --stats
to analyze transfer statistics
Comparison with Alternative Solutions
Tool | Best For | Pros | Cons |
---|---|---|---|
rsync over SSH | Incremental sync, backups | Delta transfer, secure, preserves metadata | Learning curve, SSH dependency |
scp | Simple file copies | Simple syntax, secure | No incremental transfer, slower for large files |
SFTP | Interactive file management | User-friendly, secure | Manual process, no automation |
rclone | Cloud storage sync | Multiple cloud providers, encryption | Complex configuration, resource intensive |
Security Considerations and Best Practices
Always follow security best practices when using rsync over SSH:
- Use SSH key authentication instead of passwords
- Implement proper firewall rules and SSH hardening
- Use dedicated service accounts with minimal privileges
- Enable SSH connection logging and monitoring
- Consider using jump hosts for accessing production servers
For automated backups, create a restricted SSH key:
# Create restricted key for backup purposes
ssh-keygen -t rsa -b 4096 -f ~/.ssh/backup_key -C "backup-automation"
# Add to remote server's authorized_keys with restrictions
command="rsync --server -vlogDtpre.iLsfxC . /backup/destination/",
no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding
ssh-rsa AAAAB3NzaC1yc2E... backup-automation
This configuration ensures the SSH key can only be used for specific rsync operations.
Integration with Monitoring and Automation
For production environments, integrate rsync operations with monitoring systems:
#!/bin/bash
# monitored-sync.sh
LOGFILE="/var/log/rsync-sync.log"
METRIC_FILE="/var/metrics/rsync-last-run"
echo "$(date): Starting rsync operation" >> "$LOGFILE"
START_TIME=$(date +%s)
rsync -avz --stats /source/ user@remote:/dest/ 2>&1 | tee -a "$LOGFILE"
RSYNC_EXIT_CODE=${PIPESTATUS[0]}
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
# Write metrics for monitoring system
echo "rsync_duration_seconds $DURATION" > "$METRIC_FILE"
echo "rsync_exit_code $RSYNC_EXIT_CODE" >> "$METRIC_FILE"
echo "rsync_timestamp $END_TIME" >> "$METRIC_FILE"
if [ $RSYNC_EXIT_CODE -eq 0 ]; then
echo "$(date): Rsync completed successfully in ${DURATION}s" >> "$LOGFILE"
else
echo "$(date): Rsync failed with exit code $RSYNC_EXIT_CODE" >> "$LOGFILE"
fi
Whether you’re managing a single VPS or multiple dedicated servers, mastering rsync over SSH will significantly improve your file management capabilities. The combination of security, efficiency, and flexibility makes it an indispensable tool for system administrators and developers working with remote systems.
For additional information and advanced use cases, consult the official rsync documentation and the OpenSSH manual.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.