VPS Backup Strategy: Restic + Backblaze B2

This document outlines the implementation of an encrypted, off-site backup solution for Virtual Private Servers (VPS) using Restic for backup orchestration and Backblaze B2 as the S3-compatible object storage backend.

1. Architecture Overview

The backup workflow follows a standard Push model:

  • Source: Local filesystem (Volumes, Databases, Configs).
  • Transport: Encrypted TLS stream.
  • Destination: Backblaze B2 (Immutable snapshots).

Backup Scope

CategoryPaths
Docker Data/var/lib/docker/volumes
Application Data/home/azureuser/forgejo, /home/azureuser/files, /home/azureuser/r-kcet_discord_bot/data
System Config/etc, /home/azureuser/.ssh

2. Infrastructure Setup

2.1 Backblaze B2 Configuration

  1. Bucket: Create a private bucket (e.g., shorty-backups).
  2. App Key: Generate an Application Key with Read/Write access restricted to the backup bucket.
  3. Credentials: Note the keyID and applicationKey.

2.2 Environment Configuration

On the VPS, manage secrets via a restricted environment file.

File: /root/.restic-env

# Backblaze B2 Credentials
export B2_ACCOUNT_ID="<YOUR_KEY_ID>"
export B2_ACCOUNT_KEY="<YOUR_APPLICATION_KEY>"
 
# Restic Repository Password (Encryption Key)
export RESTIC_PASSWORD="<STRONG_GENERATED_PASSPHRASE>"
 
# Repository Path
export RESTIC_REPOSITORY="b2:shorty-backups:/shorty"

Note: Ensure chmod 600 /root/.restic-env to restrict access.


3. Implementation

3.1 Installation & Initialization

# Install Restic
sudo apt update && sudo apt install -y restic
 
# Initialize the repository
source /root/.restic-env
restic init

3.2 Automation Script

The following script handles the backup, retention policy (Pruning), and health checks.

File: /usr/local/bin/server-backup.sh

#!/bin/bash
set -e
 
# Load Environment
source /root/.restic-env
 
# Define Backup Sources
BACKUP_PATHS=(
    "/var/lib/docker/volumes"
    "/home/azureuser/forgejo"
    "/home/azureuser/files"
    "/home/azureuser/r-kcet_discord_bot/data"
    "/etc"
    "/home/azureuser/.ssh"
)
 
echo "[$(date)] Starting Backup..."
 
# Execute Backup
restic backup "${BACKUP_PATHS[@]}"
 
# Apply Retention Policy (Keep 7 daily, 4 weekly)
restic forget --keep-last 7 --keep-weekly 4 --prune
 
# Verify Repository Integrity (Optional/Periodic)
# restic check
 
echo "[$(date)] Backup Completed Successfully."

Apply permissions: chmod +x /usr/local/bin/server-backup.sh

3.3 Scheduling (Cron)

Run the backup daily at 03:00 UTC.

# sudo crontab -e
0 3 * * * /usr/local/bin/server-backup.sh >> /var/log/restic-backup.log 2>&1

4. Disaster Recovery (DR) Procedure

In the event of a total instance loss, follow these steps to restore service.

Step 1: Provision & Auth

Install Restic on the new instance and recreate the /root/.restic-env file with the original credentials and RESTIC_PASSWORD.

Step 2: Full System Restore

source /root/.restic-env
 
# Restore the latest snapshot to the root directory
restic restore latest --target /

Step 3: Post-Restore Validation

  1. Permissions: Fix ownership if UID/GIDs differ on the new OS.
    chown -R azureuser:azureuser /home/azureuser
  2. Services: Reinstall the Docker engine and start the stack.
    docker-compose up -d

5. Maintenance & Monitoring

  • Snapshots: View all available recovery points: restic snapshots.
  • Storage Stats: Monitor B2 usage: restic stats.
  • Integrity: Run restic check monthly to ensure no data corruption has occurred in the remote bucket.
  • Testing: Perform a non-destructive restore test quarterly: restic restore latest --target /tmp/restore-test

6. Cross-Provider Migration & Restore

When migrating between different cloud providers (e.g., Azure to DigitalOcean or AWS), system environments and default usernames often change (e.g., azureuser vs ubuntu). To handle this safely, use a Temporary Restore workflow.

The Correct Cross-Provider Restore Method

Instead of restoring directly to /, restore to a temporary directory first to avoid overwriting system-specific files on the new VPS.

# Restore to a temporary location
restic -r b2:shorty-backups:/shorty restore latest --target /restore

Your backup will now be accessible at /restore/, allowing you to inspect and move data manually.

Step-by-Step Restore on a New VPS

  1. Prepare New VPS

    • Provision your new instance (DigitalOcean, AWS, etc.).
    • Install required tools:
      sudo apt update
      sudo apt install docker.io restic
  2. Restore to Temporary Location

    restic -r b2:shorty-backups:/shorty restore latest --target /restore
  3. Restore Docker Volumes Copy the volume data and restart the Docker engine:

    sudo rsync -a /restore/var/lib/docker/volumes/ /var/lib/docker/volumes/
    sudo systemctl restart docker
  4. Restore Application Data (User Migration) If your new server has a different user (e.g., ubuntu instead of azureuser), move the data and fix permissions:

    # Copy data from the old user's home to the new system
    sudo rsync -a /restore/home/azureuser/forgejo /home/
    sudo rsync -a /restore/home/azureuser/files /home/
     
    # If renaming the home directory:
    sudo mv /restore/home/azureuser /home/ubuntu
    sudo chown -R ubuntu:ubuntu /home/ubuntu
  5. Restore SSH Keys

    sudo mkdir -p /home/ubuntu/.ssh
    sudo cp /restore/home/azureuser/.ssh/* /home/ubuntu/.ssh/
    sudo chown -R ubuntu:ubuntu /home/ubuntu/.ssh
    chmod 600 /home/ubuntu/.ssh/*
  6. Restore Config Files (Selective) Only copy specific configurations you need; do not blindly overwrite /etc.

    sudo rsync -a /restore/etc/nginx /etc/
  7. Start Services Navigate to your project directories and run:

    docker compose up -d

Why This Method Is Better

This Restore → Inspect → Copy workflow is the professional DevOps standard. It ensures that you don’t lose data when moving between providers with different system layouts, allowing your infrastructure to remain provider-agnostic.