Originally published on go2linux.org in March 2007. Although I no longer own that domain, I am the original author. This version has been updated for 2026 and republished here on garron.me.
Introduction
If you have two servers, cross-backups are a smart safety net: if one fails, you can restore from the other. This guide uses rsync over SSH to transfer files securely and efficiently between machines.
Prerequisites
- SSH access to both machines
rsyncinstalled on both machines
apt install rsync # Debian / Ubuntu
dnf install rsync # Fedora / RHEL
Step 1 — Set up passwordless SSH login
For automated backups to work without human intervention, the backup machine needs to connect to the source server without typing a password. This requires an SSH key pair.
On the backup machine, generate a key if you do not have one:
ssh-keygen -t ed25519 -C "backup-key"
Copy the public key to the source server:
ssh-copy-id user@source-server
Test that the connection works without a password:
ssh user@source-server "echo ok"
Step 2 — Prepare the destination directory
On the backup machine, create the directory where files will be stored:
mkdir -p $HOME/backup
Step 3 — Run rsync over SSH
The basic command to copy files from the source server to the backup machine:
rsync -avz -e ssh user@source-server:/path/to/data/ $HOME/backup/
| Option | Effect |
|---|---|
-a |
Archive mode — preserves permissions, timestamps, and symlinks |
-v |
Verbose — shows files being transferred |
-z |
Compress data during transfer |
-e ssh |
Use SSH as the transport layer |
Step 4 — Keep backups in sync with --delete
To remove files from the backup that have been deleted on the source:
rsync -avz --delete -e ssh user@source-server:/path/to/data/ $HOME/backup/
--delete keeps the destination an exact mirror of the source. Use it with care — deleted files are gone from the backup too.
Step 5 — Create a reusable script
Save this as ~/backup.sh:
#!/bin/bash
rsync -avz --delete \
-e "ssh -i $HOME/.ssh/id_ed25519" \
user@source-server:/path/to/data/ \
$HOME/backup/
Make it executable:
chmod +x ~/backup.sh
Run a dry run first to verify what would be transferred without touching any files:
rsync -avz --dry-run -e ssh user@source-server:/path/to/data/ $HOME/backup/
Step 6 — Automate with cron
To run the backup every night at 2 AM, open your crontab:
crontab -e
Add this line:
0 2 * * * /home/user/backup.sh >> /home/user/backup.log 2>&1
The output is logged to backup.log so you can review what was transferred or catch errors.
Exclude files and directories
Use --exclude to skip files you do not want in the backup — caches, temp files, version control directories:
rsync -avz --delete \
--exclude='*.tmp' \
--exclude='.git/' \
--exclude='node_modules/' \
-e ssh user@source-server:/path/to/data/ $HOME/backup/
You can stack as many --exclude patterns as needed. Patterns are matched relative to the source path.
Limit bandwidth
On a shared connection, rsync can saturate the link. Use --bwlimit to cap throughput in KB/s:
rsync -avz --delete --bwlimit=5000 -e ssh user@source-server:/path/to/data/ $HOME/backup/
5000 KB/s ≈ 5 MB/s. Adjust to fit your connection and the time window you have for the backup.
Push instead of pull
All the examples above pull data from the remote server to the local machine. The same command works in reverse — push from local to remote:
rsync -avz --delete -e ssh /local/data/ user@backup-server:/home/user/backup/
Choose the direction that fits your network topology and where SSH access is set up.
Verify the backup
Check that files are being copied correctly:
ls -lh $HOME/backup/
To see how much space the backup is using:
du -sh $HOME/backup/