Files
esh-pfi-infrastructure/configs/restic/esh-docker-vm/README.md
T
vh 25e41d2ab5 fix(restic/esh-docker-vm): drop the uptime-kuma hook block that aborted every backup
Uptime Kuma moved from esh-docker-vm to ana-docker on 2026-09-22. The
pre-backup hook's fallback lookup, `docker ps | grep -E "uptime.kuma"`,
then matched nothing and exited 1. Under set -euo pipefail that aborted the
hook, and resticprofile treats a failed run-before as fatal, so no snapshot
was taken from 2026-09-22 01:00 until this fix (backup-freshness: 54h stale).

The block is removed rather than guarded because there is nothing on this
host left for it to back up. The header now records the invariant the
"blocks only WARN" promise depends on: every optional-service lookup must sit
inside an `if` test or end in `|| true`. The remaining blocks were checked
and all do.

Deployed with playbooks/esh-docker-vm-restic-drop-kuma-block.yaml (the
pre-fix hook is kept in /var/lib/restic/repair-20260923/). The live hook
hash matches the canonical copy (43e6bea8b8569602). The manual backup saved
snapshot 6ec9f74f, and backup-freshness now reports all backups fresh.
2026-09-23 08:05:47 -07:00

195 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# restic / esh-docker-vm
Primary ESH home-lab Docker host. VM on `esh-pve`. Covered by vzdump at
the hypervisor (3/3 on esh-pve after VM 108 retirement); this adds
file-level restic with app-consistent DB dumps.
Cross-site writes to `rest-server-ana` at `10.250.50.70:8000/esh-docker-vm/`.
## What's backed up
| Path | Purpose |
|---|---|
| `/opt/docker` | Compose + bind-mounted conf (~12 MB) |
| `/etc` | Host config |
| `/root` | Root's scripts / history / keys |
| `/home` | User home dirs |
| `/var/lib/docker/volumes` | HA / paperless / pgadmin / CWA / dockge / agents |
| `/var/lib/restic/stage` | DB dumps from pre-backup.sh |
## Critically excluded
- **NFS mounts from `10.0.50.50`** — `/mnt/{backup,books,compose,documents}`.
Debian NAS protects these at its own layer.
- **`/mnt/backup/docker/esh-vm-docker/*`** — offen-sidecar tarballs on
NFS; once restic proves itself for a week, retire those sidecars.
- Docker internals (`backingFsBlockDev`, `metadata.db`).
- Logs, pids, user caches.
## Pre-backup hooks
Unique to this host: most containers don't bundle sqlite3, so
`pre-backup.sh` runs sqlite3 and pg_dump **from the host** against the
volume bind-mount paths. Simpler than building custom images for HA
and pgadmin. (uptime-kuma moved to ana-docker on 2026-09-22 and its block
was removed; see the header of `pre-backup.sh` for why a stale block took
the whole backup down.)
| Service | DB | Approach |
|---|---|---|
| paperless-ngx | external Postgres `10.0.50.60` / `paperless-ng` | host pg_dump |
| home-assistant | `/var/lib/docker/.../homeassistant_v2.db` | host sqlite3 |
| pgadmin | `/var/lib/docker/.../pgadmin4.db` | host sqlite3 |
| calibre-web-automated | `/config/app.db` inside container | in-container sqlite3 (it has the binary) |
## Host prerequisites
Needs `sqlite3` and `postgresql-client` installed on esh-docker-vm:
```bash
ssh -t esh-docker-vm 'sudo apt update && sudo apt install -y sqlite3 postgresql-client restic'
```
(restic too — not installed on this host yet.)
## Deploy (one-time setup)
### 1. Install restic + db-client tooling
```bash
ssh -t esh-docker-vm 'sudo apt update && sudo apt install -y restic sqlite3 postgresql-client'
```
### 2. Add `esh-docker-vm` entry on ana-docker rest-server
```bash
ssh ana-docker '
docker run --rm httpd:2.4-alpine htpasswd -nbB esh-docker-vm "<NEW-PW>" \
>> /mnt/backup/restic/repo/ana/.htpasswd
'
# no sudo — /mnt/backup is NFS with root_squash; dir is lkraven-owned
```
### 3. Install restic creds on esh-docker-vm
```bash
ssh -t esh-docker-vm 'sudo install -d -o root -g root -m 0700 /etc/restic /var/lib/restic'
# REST URL
ssh -t esh-docker-vm 'sudo bash -c "cat > /etc/restic/restic.env && chmod 600 /etc/restic/restic.env"'
# paste: RESTIC_REPOSITORY=rest:http://esh-docker-vm:<HTPASSWD-PW>@10.250.50.70:8000/esh-docker-vm/
# Enter, Ctrl-D
# Repo passphrase
ssh -t esh-docker-vm 'sudo bash -c "cat > /etc/restic/password && chmod 600 /etc/restic/password"'
# paste: <REPO-PASSPHRASE>
# Enter, Ctrl-D
# Install DB creds (from dbcreds.env.example — edit in a temp file first)
cp configs/restic/esh-docker-vm/dbcreds.env.example /tmp/dbcreds.env
${EDITOR:-vi} /tmp/dbcreds.env # set PAPERLESS_PGPASS to real value
scp /tmp/dbcreds.env esh-docker-vm:/tmp/
ssh -t esh-docker-vm '
sudo install -o root -g root -m 0600 /tmp/dbcreds.env /etc/restic/dbcreds.env &&
rm /tmp/dbcreds.env
'
shred -u /tmp/dbcreds.env 2>/dev/null || rm -f /tmp/dbcreds.env
```
### 4. Init the repo
```bash
ssh -t esh-docker-vm '
sudo bash -c "
set -a; . /etc/restic/restic.env; set +a
restic init
"
'
# Type passphrase twice at the prompt — same as installed in /etc/restic/password.
```
### 5. Deploy pre-backup.sh
```bash
scp configs/restic/esh-docker-vm/pre-backup.sh esh-docker-vm:/tmp/pre-backup.sh
ssh -t esh-docker-vm '
sudo install -o root -g root -m 0700 /tmp/pre-backup.sh /etc/restic/pre-backup.sh &&
rm /tmp/pre-backup.sh
'
```
### 6. Test the hook by itself (without running the full backup)
```bash
ssh -t esh-docker-vm 'sudo /etc/restic/pre-backup.sh'
ssh -t esh-docker-vm 'sudo ls -lh /var/lib/restic/stage/'
```
Expected files:
- `paperless.pg_dump` — should be 1–50 MB depending on doc count
- `home-assistant.sqlite3` — ~50 MB (matches live DB size)
- `calibre-web-automated.app.db` — ~250 KB
- `pgadmin4.db` — ~200 KB
Any `WARN:` lines in the hook output indicate a block that was skipped —
read them, debug one at a time.
### 7. Install resticprofile
```bash
ssh -t esh-docker-vm '
curl -sfL https://raw.githubusercontent.com/creativeprojects/resticprofile/master/install.sh \
| sudo sh -s -- -b /usr/local/bin &&
/usr/local/bin/resticprofile version
'
```
### 8. Deploy profile
```bash
scp configs/restic/esh-docker-vm/profiles.yaml esh-docker-vm:/tmp/profiles.yaml
ssh -t esh-docker-vm '
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
'
```
### 9. Enable timers + first backup
```bash
ssh -t esh-docker-vm '
sudo resticprofile --config /etc/restic/profiles.yaml schedule --all &&
sudo resticprofile --config /etc/restic/profiles.yaml backup --verbose
'
```
Expected first snapshot: **~1–2 GB** (HA DB is the dominant file, plus
some Docker volumes). If you see much more, inspect `/home` and `/var/lib/docker/volumes`
for surprise content.
## Restoring
```bash
ssh -t esh-docker-vm '
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
"
'
```
## Follow-ups after restic is proven (separate session)
- **Rotate paperless-ngx Postgres password.** Currently `paperless-ng` —
trivially weak. Update the DB, the compose, and `dbcreds.env`.
- **Retire offen/docker-volume-backup sidecars** on paperless-ngx + pgadmin
stacks after ~1 week of clean restic runs. Delete the compose's
sidecar services + the tarballs under `/mnt/backup/docker/esh-vm-docker/`.
## Recreating the repo
Same pattern as ana-ml2 — see `configs/restic/ana-ml2/README.md`. Repo
path on ana-docker is `/mnt/backup/restic/repo/ana/esh-docker-vm/`.