Back to tutorials
Tutorial

rclone backup tutorial: Encrypted Offsite Backups for a Hosting VPS (S3/SFTP) + Restore Tests

rclone backup tutorial for VPS: encrypted offsite backups to S3 or SFTP, retention, and restore tests on Linux in 2026.

By Anurag Singh
Updated on Sep 05, 2026
Category: Tutorial
Share article
rclone backup tutorial: Encrypted Offsite Backups for a Hosting VPS (S3/SFTP) + Restore Tests

Backups usually fail in dull, easy-to-miss ways. The disk fills. A credential expires. A “successful” job uploads an empty file. This rclone backup tutorial shows a hosting-friendly setup you can trust: encrypt on the VPS, push offsite (S3-compatible or SFTP), keep sane retention, and run restore tests that prove the data is usable.

This fits a WordPress VPS, a small reseller node, or any dedicated server. Use it when you want clean offsite copies of /var/www, /etc, and other critical app data.

Examples assume Ubuntu 24.04 LTS or Debian 12/13. The same commands translate well to AlmaLinux/Rocky with minor package-name tweaks.

What you’ll build (and what you won’t)

  • Encrypted offsite backups using rclone’s crypt remote (treat the destination as untrusted).
  • Two backends: S3-compatible object storage or an SFTP “backup box”.
  • Simple retention with predictable daily naming and safe pruning.
  • Restore tests that confirm you can download, decrypt, and extract files.

What we won’t do: database-specific dumps or app-level exports. Those vary too much across stacks.

If you need full disaster recovery, pair this with snapshots and a DNS plan.

Prerequisites checklist (VPS-friendly)

  • Root or sudo access on your server
  • Enough local space for a temporary archive (or you’ll need to stream parts)
  • A remote target: S3-compatible bucket or an SFTP server
  • A time window for the first full backup (the initial upload is always the largest)

If you haven’t done a basic hardening pass, do that first. HostMyCode has a practical, no-downtime walkthrough in this VPS security audit tutorial.

Pick your hosting target: S3 vs SFTP (quick decision guide)

Both are solid. Choose based on how you operate.

  • S3-compatible object storage: best for large archives, consistent throughput, and long retention. Replication is usually straightforward.
  • SFTP backup box: best if you prefer “a server you control,” with simple quotas and a browsable filesystem.

In either case, encrypt before anything leaves the VPS. That way, a compromised destination does not automatically mean compromised backups.

Step 1: Install rclone (and lock down where it stores secrets)

On Ubuntu/Debian:

sudo apt update
sudo apt install -y rclone

Create a dedicated system user to run backups. If something breaks, this limits the blast radius.

sudo useradd --system --home /var/lib/backup --create-home --shell /usr/sbin/nologin backup
sudo mkdir -p /var/lib/backup/{work,logs}
sudo chown -R backup:backup /var/lib/backup
sudo chmod 700 /var/lib/backup

By default, rclone stores its config under ~/.config/rclone/rclone.conf. Make sure the backup user owns that file.

sudo -u backup -H rclone version
sudo -u backup -H rclone config file

You should see a path like:

/var/lib/backup/.config/rclone/rclone.conf

Step 2: Create a remote (S3-compatible) or an SFTP remote

This tutorial supports both backends. Configure one option below, then continue.

Option A: S3-compatible remote (recommended for long retention)

Run interactive config as the backup user:

sudo -u backup -H rclone config

Create a new remote (example name: objstore) and choose s3. Typical values you’ll need:

  • provider: pick the right provider, or “Other” for generic S3-compatible
  • access_key_id / secret_access_key
  • endpoint: provider-specific endpoint, e.g. https://s3.example.com
  • region: if required

Create your bucket ahead of time. Then confirm rclone can see it:

sudo -u backup -H rclone lsd objstore:

Option B: SFTP remote (backup box)

Create a new remote (example name: backupbox) and choose sftp. You’ll need:

  • host: e.g. backup.example.net
  • user: a restricted user on the backup server
  • port: usually 22
  • key file: use a dedicated SSH key

Test it:

sudo -u backup -H rclone lsd backupbox:

Step 3: Add encryption with rclone crypt (the part you shouldn’t skip)

rclone crypt does one job: it ensures the destination never receives readable data.

If someone gets into your bucket or SFTP server, they still can’t open the backups without your secrets.

Create a crypt remote (example name: offsite-crypt) that points to a folder inside your chosen remote:

sudo -u backup -H rclone config

When prompted:

  • Storage: crypt
  • remote: e.g. objstore:my-backups or backupbox:/srv/backups
  • filename encryption: standard
  • directory name encryption: true
  • password and salt: generate and store in your password manager

Quick sanity check:

sudo -u backup -H rclone mkdir offsite-crypt:healthcheck
sudo -u backup -H rclone lsf offsite-crypt:

Step 4: Build a backup set that makes sense for hosting

Don’t start with “backup the whole server.” It bloats archives and slows restores.

For most hosting VPS setups, this is a sensible baseline:

  • /etc (system and service config)
  • /var/www (or your web root)
  • /home (if you host user sites or reseller accounts outside /var/www)
  • /var/lib (only specific app dirs if needed; avoid huge caches)
  • Optional: /var/log (usually not worth offsite retention, but helpful during incidents)

If you run WordPress, confirm you can rebuild wp-config.php, uploads, and plugin/theme directories.

For safer update workflows, see this WordPress maintenance mode tutorial.

Step 5: Create a daily archive locally (tar + zstd), then upload with rclone

Generate one archive per day, then upload it. This keeps naming consistent and restores straightforward.

Install zstd:

sudo apt install -y zstd

Create a script at /usr/local/sbin/offsite-backup.sh:

sudo tee /usr/local/sbin/offsite-backup.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

BACKUP_USER="backup"
WORKDIR="/var/lib/backup/work"
LOGDIR="/var/lib/backup/logs"
DATE_UTC="$(date -u +%F)"
HOST="$(hostname -s)"

ARCHIVE_NAME="${HOST}-${DATE_UTC}.tar.zst"
ARCHIVE_PATH="${WORKDIR}/${ARCHIVE_NAME}"

REMOTE="offsite-crypt:${HOST}/daily"

mkdir -p "$WORKDIR" "$LOGDIR"

# Tune zstd level: 3-6 is usually a good compromise for VPS CPU.
# Excludes: cache folders and ephemeral runtime data.

tar \
  --create \
  --zstd \
  --file "$ARCHIVE_PATH" \
  --exclude='/var/www/*/wp-content/cache' \
  --exclude='/var/www/*/cache' \
  --exclude='/var/tmp/*' \
  --exclude='/tmp/*' \
  --exclude='/var/lib/mysql/*' \
  /etc /var/www /home \
  >"${LOGDIR}/tar-${DATE_UTC}.log" 2>&1

# Upload with retries and a visible progress line in logs.
# --checksum helps detect edge cases; for very large archives it costs extra I/O.

rclone copy \
  "$ARCHIVE_PATH" \
  "$REMOTE" \
  --retries 5 \
  --retries-sleep 15s \
  --transfers 4 \
  --checkers 8 \
  --stats 30s \
  --log-file "${LOGDIR}/rclone-${DATE_UTC}.log" \
  --log-level INFO

# Optional: verify remote sees the file size.
rclone ls "$REMOTE" --log-level ERROR | grep -F "$ARCHIVE_NAME" >/dev/null

# Keep local workspace clean. Keep today’s archive only if you want quick local restore.
rm -f "$ARCHIVE_PATH"
EOF

sudo chmod 750 /usr/local/sbin/offsite-backup.sh
sudo chown root:root /usr/local/sbin/offsite-backup.sh

Important: the script excludes /var/lib/mysql on purpose. Databases need consistent dumps or filesystem snapshots.

Tossing live database files into a tarball often produces “successful” restores that won’t start.

Step 6: Add retention safely (prune old daily archives)

On object storage, lifecycle rules usually handle retention cleanly. On SFTP, you’ll prune yourself.

Either way, rclone can delete files by age.

Create /usr/local/sbin/offsite-prune.sh (keep 30 days):

sudo tee /usr/local/sbin/offsite-prune.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

REMOTE_BASE="offsite-crypt:$(hostname -s)/daily"

# List first for visibility in logs.
rclone lsl "$REMOTE_BASE" | tail -n 20

# Delete files older than 30 days.
# Use --dry-run the first time.
rclone delete "$REMOTE_BASE" --min-age 30d --rmdirs
EOF

sudo chmod 750 /usr/local/sbin/offsite-prune.sh
sudo chown root:root /usr/local/sbin/offsite-prune.sh

Pitfall: a wrong remote path can wipe the wrong dataset. Do a dry-run once before you trust the timer:

sudo -u backup -H rclone delete offsite-crypt:$(hostname -s)/daily --min-age 30d --rmdirs --dry-run

Step 7: Schedule it with systemd timers (cleaner than cron)

systemd timers make failures visible. They also handle missed runs and keep permissions predictable.

You’ll run both jobs as the backup user.

Create the backup service

sudo tee /etc/systemd/system/offsite-backup.service >/dev/null <<'EOF'
[Unit]
Description=Offsite backup upload using rclone
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=backup
Group=backup
ExecStart=/usr/local/sbin/offsite-backup.sh
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
EOF

Create the backup timer (daily)

sudo tee /etc/systemd/system/offsite-backup.timer >/dev/null <<'EOF'
[Unit]
Description=Daily offsite backup timer

[Timer]
OnCalendar=*-*-* 02:25:00
Persistent=true
RandomizedDelaySec=600

[Install]
WantedBy=timers.target
EOF

Create the prune service + timer (weekly)

sudo tee /etc/systemd/system/offsite-prune.service >/dev/null <<'EOF'
[Unit]
Description=Prune old offsite backups using rclone
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=backup
Group=backup
ExecStart=/usr/local/sbin/offsite-prune.sh
Nice=10
EOF

sudo tee /etc/systemd/system/offsite-prune.timer >/dev/null <<'EOF'
[Unit]
Description=Weekly prune timer

[Timer]
OnCalendar=Sun *-*-* 03:10:00
Persistent=true

[Install]
WantedBy=timers.target
EOF

Enable timers

sudo systemctl daemon-reload
sudo systemctl enable --now offsite-backup.timer offsite-prune.timer
sudo systemctl list-timers --all | grep -E 'offsite-(backup|prune)'

Step 8: Run a restore test (you’re not done until this works)

Restore tests catch failures that dashboards miss. Common causes include a wrong remote path, wrong encryption secrets, permission issues, or incomplete archives.

Create a temporary restore directory:

sudo mkdir -p /root/restore-test
sudo chmod 700 /root/restore-test

List available backups:

sudo -u backup -H rclone lsf offsite-crypt:$(hostname -s)/daily | tail -n 10

Download the latest archive (adjust filename):

FILE="$(sudo -u backup -H rclone lsf offsite-crypt:$(hostname -s)/daily | tail -n 1)"
sudo -u backup -H rclone copy "offsite-crypt:$(hostname -s)/daily/${FILE}" /root/restore-test --progress

Inspect the archive contents:

sudo tar --list --zstd --file "/root/restore-test/${FILE}" | head -n 30

Do a small extraction to verify file integrity:

sudo mkdir -p /root/restore-test/out
sudo tar --extract --zstd --file "/root/restore-test/${FILE}" -C /root/restore-test/out etc/hostname etc/hosts

If this fails, go straight to the rclone logs:

sudo tail -n 60 /var/lib/backup/logs/rclone-$(date -u +%F).log

Step 9: Add basic monitoring so failures don’t hide

You don’t need a full observability stack. You do need a signal when the timer fails.

Two simple approaches:

  • systemd status checks in your existing monitoring
  • log-based alerting for “ERROR” lines in rclone logs

If you already use external checks, add a “backup freshness” endpoint. Then alert on staleness.

HostMyCode’s uptime monitoring tutorial shows a practical health-endpoint pattern you can reuse.

Common troubleshooting (fast diagnostics)

rclone says “Failed to create file system”

  • Run: sudo -u backup -H rclone config show and confirm remote names match your scripts.
  • Check DNS: resolvectl status (Ubuntu) or cat /etc/resolv.conf (Debian)
  • Validate connectivity: curl -I https://S3-ENDPOINT (S3) or ssh user@host (SFTP)

Uploads are slow or time out

  • Reduce concurrency: set --transfers 2 and --checkers 4.
  • For S3: consider --s3-chunk-size 64M on high-latency links.
  • Confirm your VPS isn’t CPU-throttled during compression; lower zstd level or schedule off-peak.

Restore test fails with “wrong password”

  • You’re using the wrong crypt remote or a different rclone config file than you think.
  • Verify the exact config path: sudo -u backup -H rclone config file.

You accidentally backed up secrets in plaintext

Stop and rotate: API keys, database passwords, and SMTP credentials. Then rebuild the chain with encryption.

If you also host email, keep DNS/email authentication tight to limit fallout. For deliverability basics, see this deliverability troubleshooting tutorial.

Hosting-aware hardening tips for your backup pipeline

  • Separate IAM credentials (S3): restrict to one bucket/prefix, allow only list/put/get, deny delete unless pruning requires it.
  • Separate SSH key (SFTP): lock it to a forced command or restricted directory if possible.
  • Don’t run backups as root unless you must. Use root only to read files, and a constrained user for upload.
  • Keep encryption secrets off the server if you can. At minimum, store them in a password manager and document a recovery path.

Where HostMyCode fits (practical hosting choices)

If you want this pattern to run quietly every night, start with a server that behaves under load.

A HostMyCode VPS is a good fit for single-site and multi-site hosting. If you’d rather hand off patching and baseline hardening, managed VPS hosting is the simpler route.

Need a VPS that can run nightly encrypted offsite backups without dragging your site during business hours? HostMyCode plans are built for hands-on administration: predictable disk I/O, stable networking, and enough headroom for compression and uploads. Start with a HostMyCode VPS, or choose managed VPS hosting if you want help keeping the platform steady while you focus on your apps.

FAQ

Is rclone encryption good enough for offsite backups?

For most hosting teams, yes. rclone crypt encrypts file contents and names before upload.

The main remaining risks are how you store the password/salt and who can access the rclone config.

Should I use snapshots instead of rclone?

Use both. Snapshots are great for fast rollback inside the same provider.

Offsite rclone backups protect you from provider-side incidents, account lockouts, and accidental deletion.

Can I back up a WordPress site with this approach?

Yes for the filesystem. For full recovery, pair it with a database dump strategy (or consistent snapshots).

At minimum, ensure you can restore wp-content and wp-config.php.

How much retention should I keep in 2026?

Common baselines: 14–30 daily backups for small sites, plus monthly “long” copies if you have compliance needs.

Start with 30 days, then adjust based on storage cost and how often you actually restore.

What’s the fastest way to confirm backups are still running?

Check the last successful timer run and remote object freshness.

On the server: systemctl status offsite-backup.service and journalctl -u offsite-backup.service --since "7 days ago".

Summary

This rclone backup tutorial set up encrypted offsite backups, straightforward retention, and a restore test you can repeat on demand.

Run it daily and you’ll catch quiet failures before they turn into an outage.

If you want predictable performance in production, deploy it on a HostMyCode VPS and keep the whole pipeline boring: a dedicated user, strong encryption, and monitoring that actually alerts. Boring restores are the restores that work.

rclone backup tutorial: Encrypted Offsite Backups for a Hosting VPS (S3/SFTP) + Restore Tests | HostMyCode