Most VPS users rely on their hosting provider's snapshot feature and assume they are covered. Snapshots are useful, but they are not a backup strategy: they live on the same provider, they do not protect against account-level events, and they rarely automate the way you need. This guide shows you how to set up automated, encrypted, deduplicated offsite backups for a VPS using Restic — an open-source backup tool that runs on every major Linux distribution and costs nothing except your storage destination.
Why Restic Instead of rsync or tar?
Traditional backup approaches work, but they have practical problems in a VPS context:
rsynccopies files as-is — no built-in encryption, no deduplication, and restoring a specific point in time requires either multiple full copies or manual snapshot management.tar + cronproduces unencrypted archives unless you layer in GPG, grows linearly with full backups, and has no built-in retention policy.
Restic addresses all of these out of the box. According to the official Restic documentation:
- Encrypted by default: every snapshot is AES-256 encrypted before leaving your server
- Content-addressed deduplication: only changed data is stored, keeping storage costs low
- Point-in-time snapshots: every backup run creates a browsable snapshot; restore any file from any point
- Multiple backends: supports local storage, SFTP, S3-compatible storage (Backblaze B2, Wasabi, Cloudflare R2), and more
- Cross-platform: single binary, no dependencies, works on any Linux distribution
Architecture of This Setup
We will configure Restic to back up selected directories from a VPS to an offsite S3-compatible destination (Backblaze B2 is used as the example because of its low cost and first-class Restic support). A daily cron job runs the backup and enforces a retention policy automatically.
- Source: your VPS (any Debian/Ubuntu/AlmaLinux/CentOS setup)
- Destination: Backblaze B2 bucket (or any S3-compatible provider)
- Schedule: daily at 02:00 server time
- Retention: keep last 7 daily, 4 weekly, 12 monthly snapshots
- Encryption: AES-256, passphrase stored in a protected file
Step 1: Install Restic
# Debian / Ubuntu
sudo apt update && sudo apt install restic -y
# AlmaLinux / CentOS
sudo dnf install restic -y
# Or download the latest binary directly
wget https://github.com/restic/restic/releases/latest/download/restic_linux_amd64.bz2
bunzip2 restic_linux_amd64.bz2
chmod +x restic_linux_amd64
sudo mv restic_linux_amd64 /usr/local/bin/restic
# Verify
restic versionStep 2: Create a Storage Bucket
On Backblaze B2 (or your preferred S3-compatible provider):
- Create a private bucket named
vps-backups-yourname - Create an application key with read and write access limited to that bucket
- Note the keyID and applicationKey — you will need them below
- Note the endpoint URL (e.g.
s3.us-west-004.backblazeb2.com)
Cloudflare R2 also works well here — it has zero egress fees, which matters if you restore frequently. The setup is identical; just substitute the R2 endpoint and credentials.
Step 3: Create a Credential File
Store all secrets in a single file that only root can read. This avoids putting credentials in cron or environment variables visible to other processes.
sudo mkdir -p /etc/restic
sudo nano /etc/restic/b2.envPaste the following, substituting your values:
export RESTIC_REPOSITORY="s3:https://s3.us-west-004.backblazeb2.com/vps-backups-yourname"
export RESTIC_PASSWORD="your-strong-passphrase-here"
export AWS_ACCESS_KEY_ID="your-b2-keyid"
export AWS_SECRET_ACCESS_KEY="your-b2-applicationkey"sudo chmod 600 /etc/restic/b2.envStep 4: Initialise the Repository
source /etc/restic/b2.env
restic initRestic will connect to your bucket and initialise the repository structure. Save the passphrase somewhere offline — losing it means losing access to all backups.
Step 5: Run Your First Backup
source /etc/restic/b2.env
restic backup /etc /home /var/www /var/lib/mysql --exclude=/var/www/*/cache --exclude=/var/www/*/tmp --verboseThe first run uploads everything. Subsequent runs only upload changed chunks — a 5 GB site with a few updated files might add only 10-50 MB per daily backup after the initial run.
Step 6: Automate with Cron
Create a backup script:
sudo nano /etc/restic/backup.sh#!/bin/bash
set -euo pipefail
source /etc/restic/b2.env
restic backup /etc /home /var/www /var/lib/mysql --exclude=/var/www/*/cache --exclude=/var/www/*/tmp --tag "daily"
# Retention policy: keep 7 daily, 4 weekly, 12 monthly
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
restic checksudo chmod +x /etc/restic/backup.shAdd a cron job:
sudo crontab -e# Run backup every day at 02:00
0 2 * * * /etc/restic/backup.sh >> /var/log/restic-backup.log 2>&1Step 7: Verify Backups and Test Restore
A backup you have never restored is a backup you cannot trust. Test at least once a month:
source /etc/restic/b2.env
# List snapshots
restic snapshots
# Browse a snapshot (substitute <snapshot-id> from the list above)
restic ls <snapshot-id> /var/www/html
# Restore a single file to /tmp
restic restore <snapshot-id> --include /var/www/html/wp-config.php --target /tmp/restore-test
# Full integrity check
restic checkMySQL / MariaDB: Back Up the Database
Backing up raw MySQL data files while the server is running can produce corrupt backups. Use mysqldump to create a consistent dump and include it in the Restic backup:
# Add to /etc/restic/backup.sh, before the restic backup line:
mkdir -p /var/backups/mysql
mysqldump --all-databases --single-transaction --quick --lock-tables=false -u root -p"$MYSQL_ROOT_PASSWORD" > /var/backups/mysql/all-databases.sqlThen add /var/backups/mysql to the Restic backup paths. The SQL dump will be included, encrypted, and deduplicated along with everything else.
How Much Storage Will This Use?
With deduplication, ongoing storage cost depends almost entirely on how much data changes each day — not on total site size. A rough estimate:
- A 10 GB VPS (mostly static files) with 200 MB changed per day: ~12 GB total after 30 days with the 7/4/12 retention policy
- A WordPress site with an active database: initial backup ~3-5 GB; daily increments ~50-200 MB
- Backblaze B2 costs approximately $0.006/GB/month (prices vary; check their current pricing)
Checklist
- Restic installed and binary verified
- Offsite bucket created with a dedicated API key (not your root account key)
- Credential file at
/etc/restic/b2.envwithchmod 600 - Repository initialised with
restic init - First manual backup completed and listed with
restic snapshots - Cron job installed and log file created
- MySQL dump included if the server runs a database
- Test restore performed — at least one file restored and verified
- Passphrase stored securely offline (password manager or printed, separate location)
- Retention policy pruning confirmed with
restic forget --dry-run
Conclusion
Automated, encrypted, offsite backups are not optional for a production VPS. Restic gives you all three in a single binary with a straightforward cron setup. The steps above take under an hour to complete, cost a few dollars a month in storage, and mean that the next time a server goes down — hardware failure, accidental deletion, or a compromised account — you have a clean, tested restore point ready to use.