Why rsync to a second drive isn't a backup strategy anymore#
If your shared hosting backup plan is a nightly rsync cron job writing to a second partition, you're one ransomware infection or disk controller failure away from losing everything your customers trust you to protect. Backups need to be incremental, encrypted, versioned, and stored off-site. Commercial solutions like Acronis Cyber Protect Cloud or JetBackup work, but they carry licensing costs that eat into already-thin reseller margins.
Restic and Rclone are two open-source tools that, combined, give you a backup system rivaling anything a $50/month JetBackup license buys — with deduplication, encryption, and support for dozens of cloud storage backends. This tutorial walks through setting up both on a production shared hosting server.
What you'll build#
By the end of this guide you'll have:
- Restic backing up every shared hosting account directory nightly
- Backups deduplicated, encrypted at rest, and versioned
- Rclone syncing those backups to an off-site S3-compatible bucket (Backblaze B2, Wasabi, MinIO, etc.)
- A simple restore procedure tested and ready
- Retention policies that keep daily, weekly, and monthly snapshots without filling your storage
Total software cost: zero. Storage cost: roughly $5/TB/month on Backblaze B2.
Prerequisites#
You need root or sudo access on the hosting server, a Backblaze B2 bucket (or any S3-compatible storage), and basic comfort with the command line. The examples below assume a Linux server with user home directories at /home/ — adjust paths if your layout differs.
Step 1: Install Restic and Rclone#
# Debian/Ubuntu
apt update && apt install -y restic rclone
# RHEL/AlmaLinux/Rocky
dnf install -y epel-release
yum install -y restic rcloneVerify both are installed:
restic version
rclone versionStep 2: Configure Rclone for your off-site storage#
Run the interactive setup:
rclone configWalk through the prompts. For Backblaze B2:
- Choose
New remote→ name itoffsite - Select
Backblaze B2from the provider list - Enter your B2 Application Key ID and Application Key
- Accept defaults and save
Test connectivity:
rclone lsd offsite:your-bucket-nameIf you see an empty listing (or the bucket contents), you're connected.
Step 3: Initialize a Restic repository on the remote storage#
Restic can talk to S3-compatible storage natively, but using Rclone as the backend gives you access to far more providers and avoids Restic's sometimes-limited S3 driver quirks.
export RESTIC_REPOSITORY=rclone:offsite:your-bucket-name/backups
export RESTIC_PASSWORD='YourStrongRepoPassword'
restic initYou should see created restic repository .... Store RESTIC_PASSWORD somewhere safe — without it, your backups are irrecoverable.
Step 4: Create the backup script#
Create /usr/local/bin/backup-hosting.sh:
#!/bin/bash
set -euo pipefail
export RESTIC_REPOSITORY=rclone:offsite:your-bucket-name/backups
export RESTIC_PASSWORD='YourStrongRepoPassword'
# Back up all user home directories
# Exclude caches, sessions, and tmp files to keep backups lean
restic backup /home \
--exclude='*/tmp/*' \
--exclude='*/.cache/*' \
--exclude='*/logs/*' \
--exclude='*/session/*' \
--tag=shared-hosting
# Retention: keep 7 daily, 4 weekly, 6 monthly snapshots
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
# Log completion
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) Backup completed" >> /var/log/hosting-backup.logMake it executable:
chmod +x /usr/local/bin/backup-hosting.shStep 5: Schedule with cron#
Add a cron job to run the backup at 2:00 AM server time:
crontab -eAdd this line:
0 2 * * * /usr/local/bin/backup-hosting.sh 2>&1 | logger -t hosting-backupThe logger command sends output to syslog so you can check results with journalctl -t hosting-backup.
Step 6: Test a restore#
Never wait for a disaster to discover your restore process doesn't work. Test it now.
List available snapshots:
restic snapshotsRestore a single account to a temporary directory:
restic restore latest --target /tmp/restore-test --include /home/usernameVerify the files are intact. Clean up when done:
rm -rf /tmp/restore-testTo restore a single file from a specific snapshot:
restic restore abc1234 --target /tmp/restore-test --include /home/username/public_html/wp-config.phpStep 7: Monitor backup health#
Add a simple check to your monitoring system (or a second cron job) that verifies the latest snapshot is less than 25 hours old:
#!/bin/bash
export RESTIC_REPOSITORY=rclone:offsite:your-bucket-name/backups
export RESTIC_PASSWORD='YourStrongRepoPassword'
LATEST=$(restic snapshots --latest 1 --json | jq -r '.[0].time')
LATEST_EPOCH=$(date -d "$LATEST" +%s)
NOW_EPOCH=$(date +%s)
AGE_HOURS=$(( (NOW_EPOCH - LATEST_EPOCH) / 3600 ))
if [ "$AGE_HOURS" -gt 25 ]; then
echo "WARNING: Latest backup is ${AGE_HOURS} hours old"
exit 1
fiHook this into your existing alerting — Nagios, Zabbix, Uptime Kuma, or even a simple webhook to Slack or Telegram.
Performance tips for large servers#
- Run backups during off-peak hours. Restic is I/O-intensive; 2–4 AM is usually safe.
- Use `--pack-size 64` on very large repositories to reduce API calls to B2/S3.
- Exclude aggressively. Session files,
/tmp, error logs, and.cachedirectories change constantly but contain no data worth backing up. - First run is slow; subsequent runs are fast. Restic's deduplication means only changed data chunks are uploaded after the initial backup.
How this fits into a hosting business#
A solid backup system is table stakes for any hosting provider. Customers expect it, regulators increasingly require it, and it's one of the clearest differentiators between a professional operation and a hobby setup. If you're running Salieno Core, you can surface backup status to customers through the control panel's monitoring hooks, giving them visibility into their own data protection without exposing the underlying infrastructure.
The total setup time for this guide is under an hour. The peace of mind — and the marketing angle of advertising encrypted, off-site, versioned backups — pays for itself immediately.
0 comments
Loading comments…