cloudflare-r2-restic-backuplisted
Install: claude install-skill jackson2w/claude-code-skills
# Restic backups to Cloudflare R2
Built and verified twice with an identical shape: `dfw` (Vultr VPS, OpenClaw workspace +
Vaultwarden + WordPress, 2026-08-16) and `hermes-agent` (Vultr VPS, Hermes gateway state,
2026-09-01). Second build took under an hour end-to-end including a real restore verification —
this skill exists so a third doesn't have to re-derive any of it.
## When restic, not rclone
`cloudflare-r2-rclone-backup` (sibling skill) mirrors a directory tree as-is — right for content
that's already static and just needs an offsite copy (a media library, exported archives). This
skill is for **application state you want point-in-time recovery of** — config, databases,
session/history stores, anything that changes daily and where "last night's version" matters,
not just "a copy exists somewhere." Restic adds client-side encryption, deduplication across
snapshots, and a real retention policy (`forget --prune`) that rclone sync doesn't have.
## The reusable shape
One `systemd` oneshot service + timer pair, one wrapper script, one Ansible playbook. Deploy
per-host under `/opt/<name>-backup/backup.sh` (root:root, mode 0700).
### Wrapper script skeleton
```bash
#!/bin/bash
set -uo pipefail
LOG_FILE=/var/log/<name>-backup.log
BACKUP_PATH=/path/to/state/dir
set -a
source /root/.config/telegram-bot.env # shared fleet alert bot, not the app's own bot
source /root/.config/<name>-restic-r2.env # RESTIC_PASSWORD, RESTIC_REPOSITORY, AWS_*
set +a
exec >>"$LOG_FIL