Ops

How to back up your VPS with rsync and cron — off-site DIY backup

Set up automated off-site backups for your VPS using rsync, SSH keys and cron. Includes retention policy, encryption and restore procedure.

Published 2026-07-15· 6 min read· Hostiger Editorial

Snapshots at your VPS provider are convenient but not enough — if the provider has an outage, you lose access to both the VPS and its snapshots. Off-site backups solve that. This guide uses rsync + cron for pure DIY backup; for managed off-site backups see Hostiger Backup-as-a-Service.

1. Set up a backup destination

The destination should be in a different data center. Options:

2. SSH key from source to destination

On the source VPS:

ssh-keygen -t ed25519 -f /root/.ssh/backup_key -N ""
ssh-copy-id -i /root/.ssh/backup_key.pub [email protected]

3. The backup script

Create /usr/local/bin/backup.sh:

#!/bin/bash
set -euo pipefail

SRC_DIRS="/etc /home /var/www /var/lib/mysql-backup /root"
DEST_HOST="[email protected]"
DEST_ROOT="/backups/$(hostname)"
DATE=$(date +%Y-%m-%d)
KEY="/root/.ssh/backup_key"

# 1. Dump MySQL first
mkdir -p /var/lib/mysql-backup
mysqldump --all-databases --single-transaction > /var/lib/mysql-backup/all-databases.sql

# 2. rsync with hardlink to previous day for space-efficient snapshots
rsync -aAXH --delete \
  --link-dest="$DEST_ROOT/latest" \
  -e "ssh -i $KEY -o StrictHostKeyChecking=no" \
  $SRC_DIRS "$DEST_HOST:$DEST_ROOT/$DATE"

# 3. Update the 'latest' symlink on the destination
ssh -i $KEY $DEST_HOST "ln -sfn $DEST_ROOT/$DATE $DEST_ROOT/latest"
chmod +x /usr/local/bin/backup.sh

4. Automate with cron

crontab -e
# Daily backup at 03:15
15 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

5. Retention policy — 7 daily / 4 weekly / 12 monthly

Add this script on the DESTINATION to prune old snapshots:

#!/bin/bash
cd /backups/$(hostname)
# Keep last 7 daily
ls -1d 20*-* | head -n -7 | while read d; do
  # Keep first snapshot of the week/month
  day=$(date -d "$d" +%w)   # 0=Sunday
  dom=$(date -d "$d" +%d)   # 01-31
  [ "$day" = "0" ] && continue
  [ "$dom" = "01" ] && continue
  rm -rf "$d"
done

6. Encrypt before shipping (optional)

For sensitive data, pipe rsync through gpg:

tar czf - $SRC_DIRS | gpg --symmetric --cipher-algo AES256 --batch --passphrase-file /root/.backup_pass \
  | ssh $DEST_HOST "cat > $DEST_ROOT/$DATE.tar.gz.gpg"

7. TEST YOUR RESTORE (most-skipped step)

An untested backup is not a backup. Once a month:

# Restore a single file
rsync -av $DEST_HOST:$DEST_ROOT/latest/var/www/site/index.html /tmp/test-restore.html
diff /var/www/site/index.html /tmp/test-restore.html

And once a quarter: fully rebuild from backup onto a spare VPS. If restore takes 3 hours because you didn't plan it, discovering that in a real incident is a bad time.

What can go wrong

Ready to try Hostiger? Deploy a VPS in under 60 seconds.

View VPS plans