Appearance
VPS Backup - Overall Concept
This document defines the architecture, schedules, and implementation protocols for the CFS Platform backup systems on the Strato Virtual Private Server (VPS).
📅 1. Backup Strategy Overview
To ensure maximum availability, disaster recovery capability, and absolute data integrity, the system implements a multi-tiered, localized, and cloud-replicated backup protocol.
Backup Paradigm
- Zero-Trust Compute: Compute resources (containers) are fully disposable; all persistent state resides in isolated docker volumes or bind-mounted directories.
- Restic Cloud Sync: Sourced from the local repository, executing directly against Google Drive via an
rclonebridge. - Client-Side Encryption: All snapshots are encrypted client-side using Restic's standard AES-256 CTR encryption scheme before leaving the VPS.
- Self-Healing Integrity: Automatic pruning, validation, and regular restic check sweeps.
🏗️ 2. Core Infrastructure Layers & Targets
| Layer | Persistent State | RTO / RPO Target | Backup Protocol |
|---|---|---|---|
| System Databases | MariaDB 10.11 instances (Active) | RTO: < 1 hour / RPO: 24 hours | Integrated database file structures (volumes) |
| System Configurations | Docker Compose & .env properties | RTO: < 10 mins / RPO: Git sync | Git repository + localized docker backup sweeps |
| Ollama Model Weights | /root/.ollama volume | RTO: < 30 mins / RPO: Stale | Download caching (re-pullable from registry) |
| Open WebUI State | Named volume data | RTO: < 30 mins / RPO: 24 hours | Daily Restic cloud snapshots |
| IDE Persistent Data | Persistent profile directory | RTO: < 30 mins / RPO: 12 hours | Automated Restic cloud snapshots |
⏱️ 3. Execution Schedules & Retention Policies
Backup Schedules
| Scope | Frequency | Execution Window | Retention Period | Destination |
|---|---|---|---|---|
| Daily Restic Backup | Daily (via Cron) | 02:00 AM UTC | 30 Days (Rolling Window) | Google Drive: backups/vps-daily |
| Monthly Full Backup | Monthly (via Cron) | Monthly | 12 Months (Rolling) | Google Drive: backups/vps-monthly |
Retention Policies (Restic Prune Specs)
- Daily Backup Snapshots: Keep the last 30 daily snapshots.
- Monthly Backup Snapshots: Keep the last 12 monthly snapshots.
🛠️ 4. Technical Implementations & Scripts
4.1 Daily Backup Script (daily-backup.sh)
This script runs daily at 02:00 AM, backing up volumes, configuration folders, and root directories.
bash
#!/bin/bash
# Daily Restic Backup Script (Google Drive)
# Target: Restic Repo via rclone bridge
set -e
set -o pipefail
# Load environment variables
if [ -f "/var/lib/backups/.env" ]; then
source "/var/lib/backups/.env"
elif [ -f "$(dirname "$0")/../config/.env" ]; then
source "$(dirname "$0")/../config/.env"
fi
RESTIC_REPO=${RESTIC_REPOSITORY:-"rclone:gdrive:backups/vps-daily"}
RESTIC_PASSWORD_FILE=${RESTIC_PASSWORD_FILE:-"/etc/restic/.password"}
LOG_FILE=${LOG_FILE:-"/var/log/restic-backup.log"}
LOCK_FILE="/var/run/restic-backup.lock"
export RESTIC_REPOSITORY="${RESTIC_REPO}"
export RESTIC_PASSWORD_FILE="${RESTIC_PASSWORD_FILE}"
export GOMAXPROCS=4
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Error handling
handle_error() {
local line=$1
log "ERROR: Script failed at line $line"
if [ -n "$ALERT_EMAIL" ]; then
local msg="/tmp/backup_error_$(date +%s).msg"
echo "Error running $(basename "$0") on $(hostname) at line $line." >> "$msg"
tail -n 50 "$LOG_FILE" >> "$msg"
mail -s "Backup FAILED: $(hostname) - $(basename "$0")" "$ALERT_EMAIL" < "$msg"
rm -f "$msg"
fi
cleanup
exit 1
}
cleanup() {
rm -f "$LOCK_FILE"
}
trap cleanup EXIT
trap 'handle_error $LINENO' ERR
if [ -f "$LOCK_FILE" ]; then
log "ERROR: Backup already in progress (lock file exists)."
exit 1
fi
touch "$LOCK_FILE"
log "===== BACKUP START ====="
restic unlock || log "Warning: Could not unlock repository..."
nice -n 19 ionice -c 3 restic backup \
--verbose \
--one-file-system \
/var/lib/docker/volumes/ \
/root/ \
/etc/ \
/opt/ \
/home/ \
--exclude="*.tmp" \
--exclude="*.log" \
--exclude="*.cache"
log "Cleaning up old snapshots..."
restic forget --keep-daily 30 --prune --verbose
log "Verifying backup integrity..."
restic check --read-data-subset=10%
log "===== BACKUP END ====="4.2 Monthly Full Backup Script (monthly-full-backup.sh)
This script captures the complete system file tree once a month, storing it in a dedicated monthly repository.
bash
#!/bin/bash
# Monthly Full-System Backup (Google Drive)
# Target: Dedicated Restic Repo
set -e
set -o pipefail
# Load environment variables
if [ -f "/var/lib/backups/.env" ]; then
source "/var/lib/backups/.env"
elif [ -f "$(dirname "$0")/../config/.env" ]; then
source "$(dirname "$0")/../config/.env"
fi
RESTIC_REPO=${RESTIC_REPOSITORY_MONTHLY:-"rclone:gdrive:backups/vps-monthly"}
RESTIC_PASSWORD_FILE=${RESTIC_PASSWORD_FILE:-"/etc/restic/.password"}
LOG_FILE="/var/log/monthly-backup.log"
export RESTIC_REPOSITORY="${RESTIC_REPO}"
export RESTIC_PASSWORD_FILE="${RESTIC_PASSWORD_FILE}"
export GOMAXPROCS=4
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log "===== MONTHLY FULL BACKUP START ====="
restic unlock || log "Warning: Could not unlock repository..."
handle_error() {
local line=$1
log "ERROR: Script failed at line $line"
if [ -n "$ALERT_EMAIL" ]; then
local msg="/tmp/backup_error_$(date +%s).msg"
echo "Error running $(basename "$0") on $(hostname) at line $line." >> "$msg"
tail -n 50 "$LOG_FILE" >> "$msg"
mail -s "Backup FAILED: $(hostname) - $(basename "$0")" "$ALERT_EMAIL" < "$msg"
rm -f "$msg"
fi
exit 1
}
trap 'handle_error $LINENO' ERR
nice -n 19 ionice -c 3 restic backup \
--verbose \
--one-file-system \
/ \
--exclude="/proc/*" \
--exclude="/sys/*" \
--exclude="/dev/*" \
--exclude="/tmp/*" \
--exclude="/run/*" \
--exclude="/mnt/*" \
--exclude="/media/*" \
--exclude="/var/cache/*"
log "Cleaning up old monthly snapshots..."
restic forget --keep-monthly 12 --prune --verbose
log "Verifying integrity..."
restic check
log "===== MONTHLY FULL BACKUP END ====="🔒 5. Security & Verification Measures
- Encryption Standard: Restic uses AES-256 in counter mode (CTR) for data encryption and Poly1305 for integrity authentication.
- Repository Locks: Restic locks the repository during writes to prevent concurrent execution conflicts.
- Pruning Runs: Automated
restic forget --prunesafely removes unneeded chunks without compromising active chains. - Alert Trigger: Any error in backup scripts triggers a mail status update payload.
🚨 6. Disaster Recovery & Restoration Procedures
Phase 1: Re-instating Host Configurations
Clone the core server configuration repository:
bashgit clone git@github.com:cfschacht-dotcom/CFS-SERVER-MANAGER.git /opt/cfs-infra
Phase 2: Restoring Container Storage Volumes
bash
# List all active snapshots on the cloud repository
restic -r rclone:gdrive:backups/vps-daily snapshots
# Restore the most recent snapshot targeting container volumes
restic -r rclone:gdrive:backups/vps-daily restore latest --target /Phase 3: Infrastructure Verification
bash
# Spin up core infrastructure
cd /opt/cfs-infra && docker compose up -d
# Spin up platform containers
cd /opt/antigravity/data/PROJECT-DEVELOPMENT/cfs-platform && docker compose up -d📊 7. Backup Topology Map
text
+--------------------------------------+
| Strato VPS Host |
+--------------------------------------+
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
+───────────────+ +───────────────+ +───────────────+
| Open WebUI | | IDE | | MariaDB |
| User Data | | Profiles | | Databases |
+───────────────+ +───────────────+ +───────────────+
│ │ │
▼ ▼ ▼
+───────────────────────────────────────────────────────────────────+
| Restic Backup Engine via Cron |
+───────────────────────────────────────────────────────────────────+
│
▼ (rclone bridge sync)
+─────────────────+
| Google Drive |
| Cloud Storage |
+─────────────────+Last Document Update: June 2026
Status: Approved & Implemented
Lead Engineer: Christian Friedrich Schacht