Files
HealthLog/docs/self-hosting/portainer
Marc-André Bombeck 308470f229 feat(encryption): back up the key, and refuse to serve when it cannot open the database
Every configured key id now has a canary in encryption_key_canaries,
checked at boot. A key that cannot open its canary, or existing data
written before the canary existed, puts the process in a refusal state:
every API route answers 503 encryption.key_mismatch, /api/health reports
reason encryption_key_mismatch, the pages render one explanation, and
neither the queue producer nor the worker starts. The process stays up
so the reason is visible instead of hiding in a crash loop.

The admin Encryption page gains a "Back up your encryption key" step:
key id and fingerprint (never the key), where the key lives per
platform, a check of a pasted copy that is compared and discarded, and
a confirmation bound to the active key id and fingerprint. The overview
gets a tile and admins get a dashboard banner while it is due.

HEALTHLOG_PLATFORM picks the platform the step opens on. Adds the
TrueNAS self-hosting page and key backup sections in the docs.
2026-10-03 18:06:28 +02:00
..

HealthLog on Portainer

HealthLog ships a Portainer app template that deploys the app and its PostgreSQL 16 database as one stack from the project docker-compose.yml.

Add the template

  1. In Portainer, go to Settings → App Templates.

  2. Set the URL to the raw template file:

    https://raw.githubusercontent.com/MBombeck/HealthLog/main/docs/self-hosting/portainer/templates.json
    
  3. Save. HealthLog now appears under App Templates.

Deploy

  1. Open App Templates → HealthLog.
  2. Fill in the variables. Generate each secret with openssl rand -hex 32 (a 64-character hex string):
    • POSTGRES_PASSWORD
    • ENCRYPTION_KEY — back this up; losing it makes encrypted data unrecoverable
    • API_TOKEN_HMAC_KEY
    • SESSION_COOKIE_SECURE — set to false for plain-HTTP / LAN access, or login silently fails. Set to true only behind an HTTPS reverse proxy.
    • NEXT_PUBLIC_APP_URL and APP_URL — how you reach the app, e.g. http://nas:3000 or https://healthlog.example.com.
  3. Deploy the stack. The app waits for PostgreSQL, runs database migrations on first boot, then starts serving.
  4. Open the app URL. The first registered user becomes the admin.

Verify the running version:

curl -s http://<host>:3000/api/version

Notes

  • Persistent state lives in one named volume (pgdata, the Postgres data dir); the app container is stateless. Back up the database to back up everything.
  • Pin a release tag (HEALTHLOG_IMAGE_REF=:vX.Y.Z) for deliberate upgrades, or track :latest. Skim the CHANGELOG and back up before upgrading. Migrations are forward-only.
  • For passive discovery you can also submit this template to the community aggregator at https://github.com/Lissy93/portainer-templates.