Close the volume-backup gap: the pg_dump covered Postgres only; the ASP.NET
DataProtection keyring (root-user credential) and uploaded docs live in the
lubelogger-{data,keys} volumes. The docker-volume-backup sidecar can't target PBS
natively, so both volumes now ride the same proxmox-backup-client job as the SQL
dump — one host/lubelogger snapshot, three .pxar archives, keep-daily 14. Backup
script+units are now installed by the Ansible playbook (idempotent, changed=0);
PBS token from ansible-vault. Restore verified: keyring XML + sentinel doc
byte-identical (sha256). Removes the now-playbook-managed standalone script/units.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LubeLogger — deployment source of truth
Vehicle & small-engine maintenance tracker. Host: docker-node01 (.186).
Postgres 18 backend (tables in the app schema). In-app auth ENABLED (root user).
Routing (file provider)
Published on the host at :8099; Traefik on node01 routes lubelogger.goattw.net
→ http://192.168.99.186:8099 via dynamic_conf.yml (see traefik-router.dynamic_conf.yml).
Edge chain: TLS (letsencrypt) → CrowdSec (global) → Authelia (authelia-auth@file,
two_factor off-LAN / bypass on-LAN). LubeLogger's own auth gates the LAN/:8099 path.
Deploy (Ansible, idempotent)
Playbook deploy-lubelogger.yml (runs from ~/ansible on ansible-control):
ansible-playbook playbooks/deploy-lubelogger.yml
Inline-compose house style: copy: the compose + community.docker.docker_compose_v2.
DB password is sourced from ansible-vault (vault_lubelogger_db_password) — never inline.
Second converge is changed=0.
Backup (PBS) — deployed BY the playbook
The backup script + systemd units are installed and enabled by deploy-lubelogger.yml
(inline, idempotent). node01, daily 03:30, one PBS snapshot (rust-usb, host/lubelogger)
with three archives in a single proxmox-backup-client job, prune --keep-daily 14:
lubelogger-db.pxar—pg_dump(app schema + data)lubelogger-data.pxar—/App/datavolume (uploads, config, cartracker.db)lubelogger-keys.pxar— ASP.NET DataProtection keyring (the ROOT USER credential + keys)
The docker-volume-backup sidecar can't target a PBS datastore natively, so the volumes
ride the same pbc job as the SQL dump (one datastore, one retention). PBS token comes from
ansible-vault (vault_lubelogger_pbs_token) → templated to /etc/lubelogger-backup.env
(root:600, NOT in git). Restore VERIFIED: SQL round-trip into throwaway postgres:18
(row-count parity) + data/keys restore (keyring XML + a sentinel doc, byte-identical sha256).
The stop-during-backup labels remain in case a sidecar is later added for a second target.
Reminders → ntfy
lubelogger-reminders-probe.{sh} + units on ansible-control (.190) — daily 07:30.
Reads /api/vehicle/info (Basic auth, creds in /etc/lubelogger-reminders.env,
root:600, NOT in git), posts a digest to ntfy topic garage only when something is
due/overdue. Subscribe to the garage topic in your ntfy app to receive it.
Diun
App carries diun.watch_repo=true + semver include_tags so a new release tag pings
the existing Diun→HA-webhook pipeline. DB (postgres:18) is watched by default (digest).
Homepage
Tile + lubelogger widget under "AI & Productivity" in
observability/homepage/services.yaml (live) — widget password via
HOMEPAGE_VAR_LUBELOGGER_PASSWORD (observability/.env, not a git repo). See
homepage-tile.yaml.
Secrets (none in this repo)
- DB password: ansible-vault (
~/ansible), and Postgres volume (already initialized). - PBS token:
/etc/lubelogger-backup.env(reuses vaultwarden token — a dedicatedlubelogger-backupPBS token would be cleaner; needs PBS root to create). - Admin/basic-auth password:
/etc/lubelogger-reminders.env+observability/.env.