<!-- skill: Restic Backups | version: 1.0.0 | description: Snapshots, forget policy, rclone remotes, cron checks, restores | category: System & Productivity -->
## Instructions
- Init once per repo: `restic -r /mnt/backup/main init` (local) or `restic -r rclone:remote:bucket/host init`; `RESTIC_REPOSITORY` + `RESTIC_PASSWORD_FILE` (600) env so cron never prompts; test `cat` of password file as the cron user.
- Snapshot: `restic backup ~/docs ~/photos --tag auto --exclude-file excludes.txt`; `--tag manual` for pre-surgery; always `--verbose` to log; `unlock` stale locks before retry (`restic unlock`).
- Forget policy: `restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune`; `--dry-run` first; run forget after backup in same job so retention is enforced daily, prune weekly (slow) not daily.
- Check integrity: `restic check` weekly, `restic check --read-data-subset=10%` monthly rotation (full read yearly); `snapshots` list + `diff <id1> <id2>` before restores.
- rclone remotes: `rclone config` (B2/S3/NAS sftp), `restic -r rclone:b2:bucket/host` prefix per host (`/laptop`, `/pi`); `rclone check` monthly quota; bandwidth `--limit-upload 5000` on home links.
- Cron + healthcheck: script `/usr/local/bin/backup.sh` → cron `0 2 * * *`; `curl -fsS -m 10 --retry 3 https://hc-ping.com/<uuid>/start` begin, `/0` ok, `/fail` on error (trap ERR); log to `/var/log/restic.log`.
- Excludes file: caches, builds, mounts (`/proc /sys /mnt /media`), `*.tmp`, `node_modules`, `.cache`, syncthing `.stversions` (optional — usually exclude, versioning is not backup); keep excludes in git.
- Pre/post hooks: dump databases first (`pg_dump > ~/dumps/db.sql` then backup `~/dumps`), LVM/ZFS snapshot for live dirs, `systemctl stop` only for 2am-tolerant services; verify dump non-empty before backup.
- Restore drills: quarterly `restic restore latest --target /tmp/restore-test --include /home/casper/docs/report.pdf` + diff; yearly full `mount` (`restic mount /mnt/restic`) browse test; untested restores are hopes.
- Keys: `RESTIC_PASSWORD_FILE=/root/.restic-pass` (600, root-only), second copy in password manager (bitwarden-selfhost); `key add` for laptop key, `key remove` on device loss; rotate yearly.
- Multi-host: one repo per trust domain (home vs work), prefix paths per host; `snapshots --host pi` filters; `tag` per dataset (`photos`, `docs`, `db`) for selective forget/restore.
- Pairs backup plugin: restic is the engine, backup plugin owns schedule/catalog; keep job names identical both sides so audits line up.
## Examples
- First backup: `export RESTIC_REPOSITORY=/mnt/backup/main RESTIC_PASSWORD_FILE=~/.restic-pass` → `restic init` → `restic backup ~/docs --tag manual`.
- Nightly: `restic backup ~/docs ~/photos --tag auto --exclude-file ~/.restic-excludes && restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6`.
- Find file: `restic snapshots --json | jq`, `restic find report.pdf --snapshots latest`, `restic restore <id> --target /tmp/r --include '*report.pdf'`.
- Mount browse: `mkdir -p /mnt/restic && restic mount /mnt/restic` → browse per-snapshot dirs.
## Workflows
1. Setup: `rclone config` (if remote) → `restic init` → excludes → manual backup → snapshot verify.
2. Automate: `backup.sh` + cron + healthcheck pings + logrotate.
3. Retain: nightly forget (no prune) + Sunday prune + monthly subset check.
4. Restore: find → restore to /tmp → diff → promote; never restore over live without snapshot-first.
5. Disaster: new disk → install restic+rclone → env vars → `snapshots` → `restore latest --target /`.
## Templates
```bash
#!/usr/bin/env bash
# /usr/local/bin/backup.sh
set -euo pipefail
export RESTIC_REPOSITORY="rclone:b2:homevault/hosts/laptop"
export RESTIC_PASSWORD_FILE="/root/.restic-pass"
HC="https://hc-ping.com/YOUR-UUID"
curl -fsS -m 10 --retry 2 "$HC/start" >/dev/null || true
trap 'curl -fsS -m 10 --retry 2 "$HC/fail" >/dev/null || true' ERR
pg_dump -U app appdb > /home/casper/dumps/appdb.sql
restic backup /home/casper/docs /home/casper/photos /home/casper/dumps \
  --tag auto --exclude-file /root/restic-excludes.txt
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6
[ "$(date +%u)" = 7 ] && restic forget --prune --keep-daily 7 --keep-weekly 4 --keep-monthly 6
restic check
curl -fsS -m 10 --retry 2 "$HC" >/dev/null
```
```text
# /root/restic-excludes.txt
/home/*/node_modules
/home/*/.cache
/home/*/.cargo
*.tmp
*.swp
/mnt
/media
/proc
/sys
/home/*/Sync/.stversions
```
```cron
# /etc/cron.d/restic-lab (log + lock guard)
0 2 * * * root flock -n /run/restic.lock /usr/local/bin/backup.sh >>/var/log/restic.log 2>&1
15 3 * * 0 root restic check --read-data-subset=10% >>/var/log/restic.log 2>&1
```
```bash
# restic env (~/.bashrc or /etc/environment for cron sourcing)
export RESTIC_REPOSITORY="rclone:b2:homevault/hosts/laptop"
export RESTIC_PASSWORD_FILE="$HOME/.restic-pass"
chmod 600 "$HOME/.restic-pass"
```
## Tools
- restic 0.16+, rclone 1.65+, healthchecks.io (or Uptime Kuma push), `jq` for snapshot JSON.
- `restic mount` (fuse3), `rclone ncdu` quota view; SARAH shell_run for dry-run forget.
## Advanced
- Copy/migrate: `restic -r repo2 copy --from-repo repo1` moves snapshots without re-upload; `rebuild-index` after interrupted prune.
- Performance: `--pack-size 64` large media, `--read-concurrency 4` on NAS, parent snapshots auto-detected (keep paths stable or dedup breaks).
- Multiple keys: `restic key list/add/remove`; compromised laptop → `remove` its key + rotate password (`key passwd`).
- Troubleshooting: lock stuck → `restic unlock` (no backup running first); slow B2 → `--limit-upload` + `--connections 8`; `wrong password` → file has trailing newline (`printf %s` rewrite); prune OOM on Pi → run prune on bigger box with same repo.
## Documentation
- `restic --help`, `restic backup --help`, `restic forget --help`.
- https://restic.readthedocs.io/
- https://rclone.org/b2/ + https://healthchecks.io/docs/
