From c94024d2387aa7b3fd41747eb7cf2b6be4a87cf5 Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Tue, 21 Apr 2026 01:19:22 -0700 Subject: [PATCH] restic/vm-esh-nas: profile + deployment guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second ESH Docker host — light (filezilla + dockge + agents, /opt/docker is 56 KB). Cross-site writes to the Anaheim rest-server since ESH has no local rest-server. Critical detail: vm-esh-nas NFS-mounts /mnt/{share,music,books,media} from 10.0.50.50 (~400 TB). Profile's exclude patterns explicitly reject those paths as a safety net on top of the source list not including them — a careless future edit to sources can't nuke the backup repo by pulling in 400 TB. Sources include /home/ (lkraven/nas/user dirs) in addition to the usual /opt/docker /etc /root /var/lib/docker/volumes — this host has multiple user accounts worth preserving dotfiles for. No pre-backup hook: no relational DBs. README walks through the full setup: install restic (not present on this host), add htpasswd entry on rest-server-ana, install creds, init, install resticprofile, schedule timers. Also flags the 3.8 GB RAM constraint. --- configs/restic/vm-esh-nas/README.md | 153 ++++++++++++++++++++++++ configs/restic/vm-esh-nas/profiles.yaml | 93 ++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 configs/restic/vm-esh-nas/README.md create mode 100644 configs/restic/vm-esh-nas/profiles.yaml diff --git a/configs/restic/vm-esh-nas/README.md b/configs/restic/vm-esh-nas/README.md new file mode 100644 index 0000000..41e3bd6 --- /dev/null +++ b/configs/restic/vm-esh-nas/README.md @@ -0,0 +1,153 @@ +# restic / vm-esh-nas + +Second Docker host at the ESH home lab — a VM on `esh-pve-nas`. Covered +two ways: + +- **VM image** via Proxmox vzdump on esh-pve-nas (5/5 covered). +- **File-level restic** (this config). Cross-site — writes to the + Anaheim rest-server at `10.250.50.70:8000/vm-esh-nas/` since the ESH + site has no local rest-server. + +## What's backed up + +| Path | Purpose | +|---|---| +| `/opt/docker` | Compose files (~56 KB — tiny) | +| `/etc` | Host config | +| `/root` | Root's scripts, ssh keys, history | +| `/home` | User home dirs (`lkraven`, `nas`, `user`) | +| `/var/lib/docker/volumes` | beszel-agent, dozzle-agent, dockge state | + +## What's critically excluded + +**`/mnt/{share,music,books,media}`** — NFS mounts from `10.0.50.50` +holding ~400 TB of media/share content. Protected at the NAS layer, +not here. The exclude-patterns in profiles.yaml are a safety net — the +source list already doesn't include `/mnt/*` — but doubly-excluded so a +careless future edit can't nuke the repo by pulling in 100 TB. + +Also excluded: docker internals, logs/pids, per-user browser and shell +caches. + +## No pre-backup hook needed + +Same as nh3-docker — no relational DBs on this host. SQLite in agent +volumes is WAL-mode + low-traffic; raw restic capture restores cleanly. + +## Deploy (one-time setup) + +### 1. Install restic (not present on this host) + +```bash +ssh -t vm-esh-nas 'sudo apt update && sudo apt install -y restic' +# or use the upstream binary if a newer version is needed: +# curl -sfL https://github.com/restic/restic/releases/latest/download/restic_*_linux_amd64.bz2 | ... +``` + +### 2. Add the client entry to the Anaheim rest-server `.htpasswd` + +If not already present from an earlier pass: + +```bash +# Generate the bcrypt line locally (httpd:2.4-alpine throwaway container) +ssh ana-docker 'docker run --rm httpd:2.4-alpine htpasswd -nbB vm-esh-nas ""' \ + | ssh -t ana-docker 'sudo tee -a /mnt/backup/restic/repo/ana/.htpasswd >/dev/null' +``` + +### 3. Install restic creds on vm-esh-nas + +```bash +ssh -t vm-esh-nas ' + sudo install -d -o root -g root -m 0700 /etc/restic /var/lib/restic +' + +# REST URL — paste from password manager (Enter, Ctrl-D) +ssh -t vm-esh-nas 'sudo bash -c "cat > /etc/restic/restic.env && chmod 600 /etc/restic/restic.env"' +# paste: RESTIC_REPOSITORY=rest:http://vm-esh-nas:@10.250.50.70:8000/vm-esh-nas/ + +# Encryption passphrase — paste from password manager (Enter, Ctrl-D) +ssh -t vm-esh-nas 'sudo bash -c "cat > /etc/restic/password && chmod 600 /etc/restic/password"' +``` + +### 4. Init the repo + +```bash +ssh -t vm-esh-nas ' + sudo bash -c " + set -a; . /etc/restic/restic.env; set +a + restic init + " +' +# Type passphrase twice at the prompt — same one you just installed. +``` + +### 5. Verify + +```bash +ssh -t vm-esh-nas ' + sudo bash -c " + set -a; . /etc/restic/restic.env; set +a + RESTIC_PASSWORD_FILE=/etc/restic/password restic snapshots + " +' +# expect: no snapshots found +``` + +### 6. Install resticprofile + +```bash +ssh -t vm-esh-nas ' + curl -sfL https://raw.githubusercontent.com/creativeprojects/resticprofile/master/install.sh \ + | sudo sh -s -- -b /usr/local/bin && + /usr/local/bin/resticprofile version +' +``` + +### 7. Deploy the profile + +```bash +scp configs/restic/vm-esh-nas/profiles.yaml vm-esh-nas:/tmp/profiles.yaml + +ssh -t vm-esh-nas ' + 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 +' +``` + +### 8. Enable timers + first backup + +```bash +ssh -t vm-esh-nas ' + sudo resticprofile --config /etc/restic/profiles.yaml schedule --all && + sudo resticprofile --config /etc/restic/profiles.yaml backup --verbose +' +``` + +Expected size: **small**, likely <500 MB. This host is light — a few +agent volumes + compose files + home dirs. If the first snapshot is +above 2 GB, check for anything unexpected in `/home` or +`/var/lib/docker/volumes` before accepting. + +Memory ceiling worth watching: vm-esh-nas has only 3.8 GB RAM. The +`min-memory: 100` global in profiles.yaml already protects against OOM +during restic's packing phase, but monitor the first backup for any +sign of restic choking on large files. + +## Restoring + +```bash +ssh -t vm-esh-nas ' + 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 + +Same pattern as ana-ml2 — see `configs/restic/ana-ml2/README.md` +"Recreating the repo" section. Repo path on ana-docker is +`/mnt/backup/restic/repo/ana/vm-esh-nas/`. diff --git a/configs/restic/vm-esh-nas/profiles.yaml b/configs/restic/vm-esh-nas/profiles.yaml new file mode 100644 index 0000000..d98ffb5 --- /dev/null +++ b/configs/restic/vm-esh-nas/profiles.yaml @@ -0,0 +1,93 @@ +# resticprofile config for vm-esh-nas. +# +# Second ESH Docker host (filezilla, dockge, agents). VM on esh-pve-nas. +# Covered by vzdump at the hypervisor level; this restic adds per-file +# restore + cross-site redundancy. +# +# Writes cross-site to the Anaheim rest-server (10.250.50.70:8000/vm-esh-nas/) +# because the ESH site has no local rest-server. Credentials live in +# /etc/restic/restic.env; passphrase in /etc/restic/password. +# +# Explicit NFS exclusions below are **critical** — this host mounts +# /mnt/{share,music,books,media} from 10.0.50.50 (hundreds of TB of +# media). They're not in the source list, but the exclude-patterns +# provide a second line of defense if the source list is ever edited +# carelessly. +# +# No DB hook needed: no relational databases on this host. Dockge / +# beszel-agent / dozzle-agent store trivial SQLite state captured raw. + +version: "1" + +global: + priority: low + ionice: true + ionice-class: 2 + ionice-level: 7 + min-memory: 100 + +default: + env-file: /etc/restic/restic.env + env: + RESTIC_PASSWORD_FILE: /etc/restic/password + initialize: false + lock: /var/lock/restic-vm-esh-nas.lock + + backup: + verbose: 1 + run-after: + - date +%s > /var/lib/restic/last-success + source: + - /opt/docker # compose files (~56 KB) + - /etc # host config + - /root # root's scripts, ssh keys, shell history + - /home # user home dirs (lkraven, nas, user) + - /var/lib/docker/volumes # beszel-agent, dozzle-agent, dockge state + exclude: + # CRITICAL: NFS mounts from 10.0.50.50 — never follow. + # These are in /mnt/, not in the source list, but pattern exclude + # protects against careless source edits. + - /mnt/share + - /mnt/music + - /mnt/books + - /mnt/media + # Docker internals + - /var/lib/docker/volumes/backingFsBlockDev + - /var/lib/docker/volumes/metadata.db + # Ephemeral / regenerable + - /opt/docker/compose/*/logs + - "**/*.log" + - "**/*.log.*" + - "**/*.pid" + # Per-user shell / app noise + - /root/.cache + - /root/.local/share/Trash + - /root/.python_history + - /home/*/.cache + - /home/*/.local/share/Trash + - /home/*/.npm + - /home/*/.mozilla/firefox/*/Cache + tag: + - host:vm-esh-nas + - site:esh + - fleet:home-lab + 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 + tag: + - host:vm-esh-nas + 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