From de1eac290417491cd4ad290630a43be3453887d8 Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Tue, 21 Apr 2026 01:13:35 -0700 Subject: [PATCH] restic/nh3-docker: profile + deployment guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds file-level restic for the NH3 Docker VM. Targets the Synology rest-server (rest-server-nh3 at 10.100.50.50:8000) as user nh3-docker — site-local writes matching the fleet pattern. No pre-backup hook needed: none of the stacks on this host (adguard, dockge, beszel-agent, dozzle-agent, portainer) run relational DBs. The SQLite state in their named volumes is WAL-mode and restores cleanly from raw restic capture. Source paths mirror ana-ml2's template (/opt/docker, /etc, /root, /var/lib/docker/volumes) with the same exclude list (docker internals, logs, pids, root's shell/caches). ~1.6 MB of compose files + small volumes — expected snapshot size a few hundred MB at most, dominated by any AdGuard query log history. README walks through reuse (existing repo + htpasswd) vs fresh init paths, resticprofile install, timer generation, and verification via the Backrest UI. --- configs/restic/nh3-docker/README.md | 162 ++++++++++++++++++++++++ configs/restic/nh3-docker/profiles.yaml | 79 ++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 configs/restic/nh3-docker/README.md create mode 100644 configs/restic/nh3-docker/profiles.yaml diff --git a/configs/restic/nh3-docker/README.md b/configs/restic/nh3-docker/README.md new file mode 100644 index 0000000..b03e7e6 --- /dev/null +++ b/configs/restic/nh3-docker/README.md @@ -0,0 +1,162 @@ +# restic / nh3-docker + +VM on `nh3-pve` at the NH3 site. Backed up two ways: + +- **VM image** via Proxmox vzdump (covered 5/5 on nh3-pve). Good for full-VM restore after catastrophic failure. +- **File-level restic** (this config). Fast per-file restore and site-resilient off-site copy. Writes to the Synology rest-server (`10.100.50.50:8000`) as user `nh3-docker`. + +## What's backed up + +| Path | Purpose | +|---|---| +| `/opt/docker` | Compose files (~1.6 MB) | +| `/etc` | Host config — systemd, ssh, chrony, apparmor, apt, etc. | +| `/root` | Root's ad-hoc scripts, shell history, ssh keys | +| `/var/lib/docker/volumes` | AdGuard confdir + workdir, beszel-agent, dozzle-agent, dockge state, portainer state | + +## Not backed up + +- `*.log`, `*.pid`, `.../logs/` directories +- `/root/.cache`, `/root/.npm`, shell-noise caches + +## No pre-backup hook needed + +Unlike ana-docker, nh3-docker runs no relational databases. The volumes +captured above contain SQLite files for dockge / beszel-agent / +dozzle-agent / portainer — all low-transaction, WAL-mode, and restic's +raw-file capture restores cleanly. + +AdGuard config lives in `/var/lib/docker/volumes/adguard_adguard-confdir/` +as plain YAML. No consistency concerns. + +## Deploy (one-time setup) + +### 1. Check for existing repo + htpasswd + +The Synology rest-server at `10.100.50.50` may already have an `nh3-docker` +entry in its `.htpasswd` and a repo at `/nh3-docker/` from an earlier +setup pass. See `stacks/rest-server-nh3/README.md` for the Synology-side +layout. + +If a repo + htpasswd exist and you have the passphrase: follow the +**reuse** path (skip init, install the existing secrets). + +If not: follow the **fresh** path below. + +### 2. Install restic creds on nh3-docker + +```bash +ssh -t nh3-docker ' + sudo install -d -o root -g root -m 0700 /etc/restic /var/lib/restic +' + +# REST URL (with HTTP basic-auth creds embedded) — paste from password manager +ssh -t nh3-docker 'sudo bash -c "cat > /etc/restic/restic.env && chmod 600 /etc/restic/restic.env"' +# paste: RESTIC_REPOSITORY=rest:http://nh3-docker:@10.100.50.50:8000/nh3-docker/ +# Ctrl-D + +# Encryption passphrase — paste from password manager +ssh -t nh3-docker 'sudo bash -c "cat > /etc/restic/password && chmod 600 /etc/restic/password"' +# paste: +# Ctrl-D +``` + +### 3. Verify creds against the repo + +```bash +ssh -t nh3-docker ' + sudo bash -c " + set -a; . /etc/restic/restic.env; set +a + RESTIC_PASSWORD_FILE=/etc/restic/password restic snapshots + " +' +``` + +Expected: either a list of existing snapshots, or `no snapshots found` +on a fresh repo. Both are fine. + +If you get `wrong password or no key found`, the passphrase doesn't +match. Check your password manager or follow the "Recreating the repo" +path below. + +### 4. Fresh-init (only if no repo exists yet on the Synology) + +```bash +ssh -t nh3-docker ' + sudo bash -c " + set -a; . /etc/restic/restic.env; set +a + restic init + " +' +# enter passphrase twice at the prompt +``` + +### 5. Install resticprofile + +```bash +ssh -t nh3-docker ' + curl -sfL https://raw.githubusercontent.com/creativeprojects/resticprofile/master/install.sh \ + | sudo sh -s -- -b /usr/local/bin + /usr/local/bin/resticprofile version +' +``` + +### 6. Deploy the profile + +```bash +scp configs/restic/nh3-docker/profiles.yaml nh3-docker:/tmp/profiles.yaml + +ssh -t nh3-docker ' + sudo install -o root -g root -m 0644 /tmp/profiles.yaml /etc/restic/profiles.yaml && + rm /tmp/profiles.yaml && + sudo resticprofile --config /etc/restic/profiles.yaml show +' +``` + +### 7. Enable systemd timers + +```bash +ssh -t nh3-docker ' + sudo resticprofile --config /etc/restic/profiles.yaml schedule --all && + systemctl list-timers "resticprofile*" +' +``` + +### 8. First backup + +```bash +ssh -t nh3-docker 'sudo resticprofile --config /etc/restic/profiles.yaml backup --verbose' +``` + +Expected size: **a few hundred MB** (adguard's data dir can hold cache + +query log, which is the bulk). If you see >2 GB on first run, check for +old AdGuard query logs under `/var/lib/docker/volumes/adguard_adguard-workdir/` +and decide whether to exclude them. + +Verify in Backrest UI (`http://10.250.50.70:9898`) — `nh3-docker` repo +should show the new snapshot within a minute. + +## Restoring + +```bash +ssh -t nh3-docker ' + sudo bash -c " + set -a; . /etc/restic/restic.env; set +a + RESTIC_PASSWORD_FILE=/etc/restic/password \ + restic restore --target /tmp/restore latest --path /opt/docker + " +' +``` + +## Recreating the repo (lost passphrase) + +Same pattern as ana-ml2 but targets the Synology rest-server. See +`configs/restic/ana-ml2/README.md` for the wipe-and-reinit recipe; +substitute: + +- rest-server host `10.100.50.50` instead of `10.250.50.70` +- repo path `/nh3-docker/` under the Synology's rest-server data root + (location depends on that stack's `DATA_DIR` — see + `stacks/rest-server-nh3/README.md`) +- SSH into the Synology directly requires enabling SSH in DSM + key + setup (tabled in an earlier session) diff --git a/configs/restic/nh3-docker/profiles.yaml b/configs/restic/nh3-docker/profiles.yaml new file mode 100644 index 0000000..c1be58b --- /dev/null +++ b/configs/restic/nh3-docker/profiles.yaml @@ -0,0 +1,79 @@ +# resticprofile config for nh3-docker. +# +# nh3-docker is a VM on nh3-pve, so its disk image IS captured by vzdump +# at the hypervisor layer. This file-level restic is additive: it gives +# fast per-file restore without mounting the VM image, and ships to the +# site-local rest-server for location-resilient recovery. +# +# Writes to the Synology rest-server at 10.100.50.50:8000 as user +# `nh3-docker`. The full REST URL (with HTTP basic-auth creds) lives in +# /etc/restic/restic.env. The client-side encryption passphrase lives in +# /etc/restic/password. +# +# No DB dumps needed. None of the stacks on this host (adguard, dockge, +# beszel-agent, dozzle-agent, portainer) run a relational DB — AdGuard +# stores config as YAML, the rest use tiny SQLite state in their volumes +# which restic captures raw (WAL-mode SQLite recovers cleanly). + +version: "1" + +global: + priority: low + ionice: true + ionice-class: 2 + ionice-level: 7 + min-memory: 100 + +default: + env-file: /etc/restic/restic.env # RESTIC_REPOSITORY=rest:http://user:pw@… + env: + RESTIC_PASSWORD_FILE: /etc/restic/password + initialize: false # repo created manually by `restic init` + lock: /var/lock/restic-nh3-docker.lock + + backup: + verbose: 1 + run-after: + - date +%s > /var/lib/restic/last-success + source: + - /opt/docker # compose files (~1.6 MB on this host) + - /etc # host config (systemd, adguard upstream config, etc.) + - /root # root shell history, ssh keys, ad-hoc scripts + - /var/lib/docker/volumes # adguard config, agent state, dockge state, etc. + exclude: + - /var/lib/docker/volumes/backingFsBlockDev + - /var/lib/docker/volumes/metadata.db + - /opt/docker/compose/*/logs + - "**/*.log" + - "**/*.log.*" + - "**/*.pid" + - /root/.cache + - /root/.local/share/Trash + - /root/.npm + - /root/.python_history + tag: + - host:nh3-docker + - site:nh3 + - fleet:pfi + schedule: "*-*-* 01:00:00" + schedule-permission: system + schedule-log: /var/log/restic-backup.log + + forget: + keep-daily: 7 + keep-weekly: 4 + keep-monthly: 12 + keep-yearly: 3 + # NOTE: no `prune: true` — rest-server runs with --append-only on both + # sites. See README.md "Prune ceremony". + tag: + - host:nh3-docker + schedule: "*-*-* 03:00:00" + schedule-permission: system + schedule-log: /var/log/restic-forget.log + + check: + read-data-subset: 10% + schedule: "Sun *-*-* 05:00:00" + schedule-permission: system + schedule-log: /var/log/restic-check.log