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
  • rsync installed 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/