Files
esh-pfi-infrastructure/configs/restic/esh-docker-vm/README.md
T
vh 6e8da46a28 fix(restic/esh-docker-vm): stop dumping paperless's Postgres from this host
Operator decision. paperless-ngx's database lives on esh-vm-db and is backed
up at the source by that host's fail-closed pg_dumpall. esh-docker-vm's
second copy had failed auth every night since 2026-04-24 behind a WARN. Its
`> paperless.pg_dump` redirect left a 0-byte file in every snapshot
(confirmed in snapshot 6ec9f74f), which looked like a dump but held nothing.

The block was the only consumer of /etc/restic/dbcreds.env, so the creds
loader is gone and the template dbcreds.env.example is deleted. The host
file was moved (not deleted) to /var/lib/restic/repair-20260923/.
Paperless's media volumes are still captured under /var/lib/docker/volumes.

Also fixes ownership. elway's sudo upload does scp-as-user then `sudo mv`,
so the hook deployed at 08:04 landed infra-ops:infra-ops even though root
executes it. Both esh-docker-vm playbooks now chown it back to root and
verify root:root 700.

Verified: the live hook hash matches canonical (e0d3ddcef1bddf43), and
the manual backup saved snapshot decfae71 with 3 staged dumps and no WARN
lines.
2026-09-23 09:18:03 -07:00

196 lines
6.3 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 **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.)
**paperless-ngx's database is NOT dumped here** (removed 2026-09-23, operator
decision). It lives on esh-vm-db (`10.0.50.60`) and is backed up at the source
by that host's fail-closed `pg_dumpall` — see `configs/restic/esh-vm-db/`.
The host-side `pg_dump` this hook used to run had failed auth every night
since 2026-04-24 behind a WARN, and its `> paperless.pg_dump` redirect left a
**0-byte file in every snapshot** that looked like a dump. It was the only consumer of
`/etc/restic/dbcreds.env`, so the creds file and its template went too.
Paperless's *media* volumes are still captured under `/var/lib/docker/volumes`.
| Service | DB | Approach |
|---|---|---|
| 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` installed on esh-docker-vm (`postgresql-client` was only for
the removed paperless dump; it is still installed, and harmless):
```bash
ssh -t esh-docker-vm 'sudo apt update && sudo apt install -y sqlite3 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'
```
### 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
```
### 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:
- `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.** Was `paperless-ng` —
trivially weak. Update the DB and the compose (no copy lives on this
backup path any more). The removed backup copy failed auth from
2026-04-24 on, so it may already have changed at the DB side; confirm
before assuming.
- **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/`.