Decided 2026-08-28: instances are protected by replication (sdb now, nuc after FTTH, ks2 push in between), their data/DBs/configs by restic-data — a third copy of instance filesystems in S3 was not worth the moving parts. backup-strategy.md now explains the replication-vs-backup split and the rebuild path when no replica survives; restic-backup.md §6 is marked SHELVED (script and empty repo kept). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7.0 KiB
ks4 backup strategy (2026-08)
Audience: anyone with root on ks4 who needs to know what is protected, where, by which tool, and how to check it. Details live in the linked docs; this page is the map.
Two tools, no more
| tool | job | why this one |
|---|---|---|
incus copy --refresh |
replicate whole instances (ready-to-start copies) | ZFS-incremental, native to the platform, restores are incus start |
| restic | off-site backups to S3 (files, database dumps, instance trees) | dedup + encryption, local metadata cache → a night costs only the churn (restic-backup.md) |
plakar was evaluated first and replaced (its nightly cost scaled with tree size — PlakarKorp/plakar#2338); the old backup server ks2 is being retired (decommission by Sep 30, 2026 — ks2/plan.md): it still holds an ageing copy of the instances until the nuc leg below takes over.
Status 2026-08-28: the local replica leg and the S3 data leg are live. The nuc pull leg is waiting for FTTH (expected before end of September); until it lands, the ks2 push is re-enabled as an interim off-site copy of the instances. Backing up instance images to S3 was designed and shelved — S3 holds the data, the databases and the incus configuration, which is what a rebuild needs.
The map
ks4 (OVH) off-site
┌────────────────────────────────────────────┐
│ live instances pool `data` (sda) │
│ nextcloud, seafile, mail, git, ... │
│ │ │
│ │ 01:00 incus copy --refresh │ nuc (home LAN, via WireGuard)
│ ▼ │ ┌───────────────────────────┐
│ replicas (stopped) pool `backup` (sdb) │────▶│ 05:00 incus copy (pull) │
│ project `backup` ready to start │ │ pool `ks4backup` (USB) │
│ │ └───────────────────────────┘
│ ──────────────────────────────────────── │
│ │ OVH Object Storage (S3, sbg)
│ 05:00 restic-backup.sh │ ┌───────────────────────────┐
│ • DB dumps (MariaDB/PostgreSQL, auto) │────▶│ bucket restic-data │
│ • incus config + global DB dump │ │ everything needed to │
│ • data trees (restic-paths) │ │ rebuild: dumps + data │
│ │ └───────────────────────────┘
│ Sun 14:00 restic-maintenance.sh │
│ • prune + check (rotating full verify) │
└────────────────────────────────────────────┘
Two different kinds of protection, on purpose:
- instances (the running systems) are protected by replication —
a ready-to-start copy on ks4's second disk and, after FTTH, on nuc.
Restoring one is
incus copy+incus start. - the data inside them (files, databases, incus configuration) is protected by backup — encrypted, deduplicated, versioned on S3, independent of ks4 and of the disks. Restoring means recreating the container (its config is in the S3 dumps, its install steps are in this repo) and pouring the data back.
Backing up whole instance images to S3 as well was designed (ks4/restic-backup.md §6) and shelved: it duplicates data already covered, and the replication legs already give instances two homes.
Schedule (root crontab on ks4)
| when | what | log |
|---|---|---|
| 01:00 daily | incus-copy.sh -p backup -s backup — refresh all replicas onto sdb |
/var/log/incus-copy.log |
| 02:00 daily | incus-copy.sh -d ks2 -m push — interim off-site replicas, until the nuc leg replaces it |
/var/log/incus-copy.log |
| 03:00 daily | instance snapshots (incus profile, 7-day expiry) — what keeps the refreshes incremental | incus info <inst> |
| 05:00 daily | restic-backup.sh — dumps + data trees → S3 |
/var/log/restic-backup.log |
| 05:00 daily (nuc) | nuc pulls all replicas over WireGuard | nuc: /var/log/incus-copy-ks4.log |
| Sun 14:00 | restic-maintenance.sh — prune (capped), structure check, 1/52 data verification |
/var/log/restic-maintenance.log |
| 1st of month 06:00 / quarterly 15th | seafile GC dry-run report / real GC (ks4/seafile-gc.md) | /var/log/seafile-gc.log |
Retention on S3: 14 daily, 8 weekly, 6 monthly snapshots.
"Did last night work?" — the 30-second check
grep -aE "done \(rc=|FAILED" /var/log/incus-copy.log | tail -2
grep -aE "snapshot .* saved|done \(rc=|failed" /var/log/restic-backup.log | tail -3
rc=0 everywhere = fine. Any failed/FAILED line names the culprit
(instance, database or path). All scripts exit non-zero on any error,
never silently.
Restoring
- A whole instance, fast (same box):
incus copy backup:<inst>style — copy the replica from projectbackupback intodefault(ks4/incus-copy.md); from nuc the same via the remote. - A file or directory (any date within retention):
restic -r s3:s3.sbg.io.cloud.ovh.net/restic-data restore <snapshot> --target /backup/restore-x --include <path>(never restore into/tmp— it is RAM). Env:. /root/.restic-env. - A database: restore the
.sqldump fromrestic-data(/backup/dumps/mariadb/<inst>/<db>.sql,grants.sqlfor users), load it withincus exec <inst> -- mariadb < dump.sql. - An instance when no replica survives (worst case: ks4 and the
replica sites are gone): recreate the container from its page in
ks4/ (the doc is the install script), restore its data
trees and database dumps from
restic-data, and use the incus configuration captured nightly in the dump tree (/backup/dumps/incus/incus-global-db.sql) to check devices, profiles and addresses.
Secrets you need for any of this: /root/.restic-passphrase and the S3
keys in /root/.restic-env — both are in the password manager;
without the passphrase the S3 buckets are unreadable.
Adding something to the backups
New instances are picked up automatically by the replica and
instance legs (all instances, opt-out only). Databases are
auto-discovered. Only data trees need one line in
restic-paths — see new-container.md.