VPS Backup

Data & APIs

Automated daily VPS backup using restic — backs up OpenClaw workspace, SSH keys, project code, and session transcripts. Configures encrypted incremental snapshots with retention policies and optional offsite push via rclone. Use when setting up a new VPS backup system, verifying existing backups, restoring files, or scheduling periodic automated backups.

Install

openclaw skills install vps-backup

VPS Backup Skill

Automated daily backup for OpenClaw VPS deployments using restic — encrypted, incremental, deduplicating snapshots with retention management and optional offsite push.

What Gets Backed Up

PathContentsWhy
~/.openclawWorkspace, memory, sessions, configsCore agent state
~/.config/opencodeAgents, skills, OpenCode modelsAgentic coding setup
~/.sshSSH keysAccess to all services
~/.npm-globalGlobal npm packagesTools installed
~/workspace/projectsAll project source codeYour work
Session transcriptsExported via export_sessions.pyHuman-readable chat history

Excluded (reconstructable): node_modules/, __pycache__/, *.pyc, *.log, tmp/, *.sqlite, .cache/

Setup

1. Install restic

# Linux (others: https://restic.net/install/)
curl -LO https://github.com/restic/restic/releases/latest/download/restic_linux_amd64.tar.gz
tar xzf restic_linux_amd64.tar.gz
sudo mv restic /usr/local/bin/
restic version

2. Install rclone (for offsite push — optional)

curl -LO https://downloads.rclone.org/rclone-current-linux-amd64.zip
unzip rclone-current-linux-amd64.zip
sudo cp rclone-linux-amd64/rclone /usr/local/bin/
rclone version

3. Configure the script

Edit the top config section of scripts/vps-backup.sh:

BACKUP_ROOT="/home/dev/backup/vps-daily"    # local backup root
BACKUP_PATHS=(                                    # what to back up
    "/home/dev/.openclaw"
    "/home/dev/.config/opencode"
    "/home/dev/.ssh"
    "/home/dev/.npm-global/lib/node_modules"
    "/workspace/projects"
)
SESSION_EXPORT="/home/dev/.openclaw/workspace/scripts/export_sessions.py"

4. Set encryption password

# Generate a strong password
openssl rand -base64 32 > ~/.backup-password
chmod 600 ~/.backup-password

5. (Optional) Configure rclone for offsite push

rclone config
# Follow prompts to add your cloud storage (Backblaze B2, Google Drive, etc.)

6. Schedule daily run

# Add to crontab (runs at 3am UTC daily)
0 3 * * * export BACKUP_PASSWORD=$(cat ~/.backup-password) && export PATH="$HOME/bin:$PATH" && bash /path/to/vps-backup.sh >> /var/log/vps-backup.log 2>&1

Or schedule via OpenClaw cron:

every: 24h | sessionTarget: isolated | model: glm-5
message: "Run: export BACKUP_PASSWORD=$(cat ~/.backup-password) && export PATH=\"$HOME/bin:$PATH\" && bash /home/dev/scripts/vps-backup.sh"

Daily Usage

# Run backup manually
export BACKUP_PASSWORD=$(cat ~/.backup-password)
export PATH="$HOME/bin:$PATH"
bash /home/dev/scripts/vps-backup.sh

# Check snapshot count
export RESTIC_PASSWORD=$(cat ~/.backup-password)
export PATH="$HOME/bin:$PATH"
restic snapshots --repo /home/dev/backup/vps-daily/restic-repo

# Verify backup integrity
restic check --repo /home/dev/backup/vps-daily/restic-repo

# List repo size
du -sh /home/dev/backup/vps-daily/

Restore

# Restore latest snapshot of a specific path
export RESTIC_PASSWORD=$(cat ~/.backup-password)
export PATH="$HOME/bin:$PATH"
restic restore latest \
  --repo /home/dev/backup/vps-daily/restic-repo \
  --target /tmp/restore \
  --path /home/dev/.openclaw

# List snapshots for a specific date
restic snapshots --repo /home/dev/backup/vps-daily/restic-repo \
  --tag date-2026-03-31

# Restore a specific snapshot by ID
restic restore abc123 \
  --repo /home/dev/backup/vps-daily/restic-repo \
  --target /tmp/restore

Offsite Push

Set the RCLONE_DEST environment variable before running:

# Backblaze B2 example:
export RCLONE_DEST="b2:my-bucket/vps-backups"
export BACKUP_PASSWORD=$(cat ~/.backup-password)
export PATH="$HOME/bin:$PATH"
bash /home/dev/scripts/vps-backup.sh
# Output includes: "Offsite push done ✓"

# Google Drive:
export RCLONE_DEST="gcache:openclaw-backups"

The script automatically detects rclone and RCLONE_DEST and syncs after each backup.


Retention Policy

LevelKeep
Daily7
Weekly4
Monthly6

Old snapshots are pruned automatically after each run.


Health Check

The script checks for at least one snapshot in the last 26 hours. If missing, it logs a HEALTH FAILED error.

Add a monitoring check to your alerting:

# Alert if no recent backup
RECENT=$(RESTIC_PASSWORD=$(cat ~/.backup-password) restic snapshots \
  --repo /home/dev/backup/vps-daily/restic-repo \
  --json 2>/dev/null | python3 -c "
import sys,json,datetime
cutoff=datetime.datetime.now(datetime.timezone.utc)-datetime.timedelta(hours=26)
print(sum(1 for s in json.load(sys.stdin)
  if datetime.datetime.fromisoformat(s['time'].replace('Z','+00:00'))>cutoff))
")
if [ "$RECENT" -eq 0 ]; then
  echo "ALERT: No backup in 26h!"
fi

Files

  • scripts/vps-backup.sh — the backup script
  • scripts/export_sessions.py — session transcript exporter (optional but recommended)
  • docs/config.md — environment variable reference