Data¶
Two trees per app — config and data — cleanly separated so backups can target the bytes that change. This document is canonical; paths elsewhere should be read against it.
The rule¶
| tree | holds | changes | backed up |
|---|---|---|---|
| config | compose files, .env, .env.example, scripts, unit drop-ins |
rarely, deliberately | git (the repo is the config backup) + nightly config snapshot |
| data | application state: databases, libraries, uploads, caches, tokens | constantly | nightly restic |
Naming: lowercase, no separators in the app name, one directory per app, data directory named exactly like the config directory.
The roots¶
| node | config root | data root |
|---|---|---|
vps-apps |
/opt/homelab/vps-apps/<app>/ (tracked) + /opt/docker/<app>/ (untracked) |
/opt/homelab-data/<app>/ |
vps-net |
/opt/homelab/vps-net/<app>/ |
/opt/homelab-data/<app>/ |
pi-home |
systemd units + /etc/<app>/ |
/mnt/dietpi_userdata/<app>/ |
Ground rules¶
- No application data under
/opt/docker. If a directory there holds anything but config, it is a violation; move it to the node's data root. - Named Docker volumes on vps-apps become bind mounts into
/opt/homelab-data/<app>/. A volume you cannot see in the filesystem is a volume you cannot back up with a path-based plan. - Cloud mounts (
/mnt/gdrive,/mnt/altdrive,/mnt/pcloud) are not app data. External sources. An app may point at them read-only (e.g. romm's library on pCloud); it may not store its state there. /home/jmrdezand/home/dietpiare not data roots.
Backup split¶
Two hosts × two branches × two locations. Restic repos are encrypted and
versioned. Repos are named <host>-<branch>-<loc>; the tree is nested on both
locations:
pi-hdd (pi-home HDD, /mnt/pi-hdd/backups — physical)
gdrive:backups (— off-site, same shape)
<host>/{config,data}/
| host | engine | schedule (Madrid) | retention |
|---|---|---|---|
vps-apps |
Backrest (Docker, 4 plans) | config 04:00 pihdd / 05:00 gdrive · data 03:30 pihdd / 04:30 gdrive | config d14/w8/m12 · data d7/w4/m6 |
pi-home |
native restic-pihome-backup + timers |
data 02:00 / config 02:30 (node clock UTC: 00:00/00:30) | config d14/w8/m12 · data d7/w4/m6 |
- pi-hdd is the fast local leg; gdrive the off-site leg (~1 h later).
- One repo password per branch, shared across both locations, stored on the
node only (vps-apps:
/opt/docker/backrest/repo-password-{config,data}, pi-home:/etc/restic-backups/{config,data}.pass, both chmod 600). - All eight repos verified. pi-home has no Docker and no Backrest —
restic-backup@.servicetemplate unit + two timers, ntfy push on failure, weekly forget+prune withMemoryMax=300M. - RomM assets ride the vps-apps data plans from the pCloud FUSE mount. A FUSE
hang can stall a plan for up to 1 h/file; recovery is
systemctl restart rclone-pcloud.service.
Not backed up (deliberately)¶
pi-home/mnt/pi-hdd/share/{open,temp}— the WebDAV drop (vps-apps/webdav/). Scratch data, disposable.- Crucially: nothing else is excluded by design. If a new app holds data, it joins the restic set. No exceptions.
OpenCloud — stays local¶
/opt/homelab-data/opencloud/ on vps-apps, backed up nightly via the data
branch (pihdd + gdrive). Keep it on the local disk: a network FS (NFS) panics
the reva/NATS dataprovider in the ocis container — this was tried, failed, and
reverted. Do not retry.