mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
Merge remote-tracking branch 'origin/main' into feat/v140-fixes
# Conflicts: # docs/api/openapi.yaml
This commit is contained in:
commit
cd3c0b7de2
74 files changed
+4140
-508
No files matched your search
+544
-448
File diff suppressed because it is too large.
Load diff
@@ -79,6 +79,14 @@ dev --create-only --name vX_Y_Z_rollback_<col>`), edit the SQL,
|
||||
commit, and re-deploy. Never `migrate resolve --rolled-back` against
|
||||
production unless you've taken a fresh `pg_dump` first.
|
||||
|
||||
## Catalog templates
|
||||
|
||||
A new required environment variable, or a change to the compose shape, needs a
|
||||
matching pull request to the TrueNAS apps catalog in the same release cycle
|
||||
(and an update to `docs/self-hosting/unraid/healthlog.xml` and
|
||||
`docs/self-hosting/portainer/templates.json`). See
|
||||
`docs/self-hosting/truenas.md` for what the catalog template carries.
|
||||
|
||||
## Verify the served version
|
||||
|
||||
The queued-deploy status is **not** the source of truth — the version
|
||||
|
||||
@@ -207,6 +207,13 @@ ps` — the `app` healthcheck polls `/api/health` every 30 seconds
|
||||
the container unhealthy if Postgres is still
|
||||
starting. Tail `docker compose logs db` to confirm Postgres came up
|
||||
cleanly.
|
||||
- **The login page says "Signing in cannot complete on this page".** The
|
||||
server sets its session cookie with the `Secure` flag (the production
|
||||
default) and the page was opened over plain `http://`, where the browser
|
||||
would drop it. Set `SESSION_COOKIE_SECURE=false` for a server reached only
|
||||
over HTTP on a private network, or open the `https://` address (behind a TLS
|
||||
proxy, make sure it forwards `X-Forwarded-Proto: https`). The sign-in is
|
||||
refused before any password, code or ticket is used.
|
||||
- **OAuth callbacks loop back to localhost.** Confirm `APP_URL` and
|
||||
`NEXT_PUBLIC_APP_URL` both point at the public hostname, not at
|
||||
`localhost`, and restart `app` after the change.
|
||||
@@ -226,6 +233,40 @@ ps` — the `app` healthcheck polls `/api/health` every 30 seconds
|
||||
`pull_policy: always` on the `app` service, and verify the running
|
||||
build with `GET /api/version` (it returns `version` + `buildSha`).
|
||||
|
||||
## Back up your encryption key
|
||||
|
||||
`ENCRYPTION_KEY` (or the `ENCRYPTION_KEYS` map) is not stored in the database.
|
||||
Without it, the encrypted parts of the database and every in-database backup
|
||||
cannot be read. Keep a copy outside the server, then confirm it under Admin,
|
||||
Encryption: the step shows the key id and a fingerprint (the first 12 hex
|
||||
characters of SHA-256 over the key) and can check a pasted copy without
|
||||
storing it. Admins see a dashboard reminder until the active key is confirmed.
|
||||
|
||||
| Platform | Where the key is set |
|
||||
| --------- | --------------------------------------------------------------- |
|
||||
| Compose | `.env` next to `docker-compose.yml` |
|
||||
| TrueNAS | Apps, HealthLog, Edit, Environment |
|
||||
| Coolify | the application's Environment Variables |
|
||||
| Unraid | the container template (Docker tab, Edit) or the Compose `.env` |
|
||||
| Portainer | the stack's Environment variables |
|
||||
|
||||
Set `HEALTHLOG_PLATFORM` (`compose`, `truenas`, `coolify`, `unraid`,
|
||||
`portainer`) to open the step on your platform's instructions.
|
||||
|
||||
To compute the fingerprint of your copy:
|
||||
|
||||
```bash
|
||||
echo -n "<your key>" | xxd -r -p | sha256sum | cut -c1-12
|
||||
```
|
||||
|
||||
**HealthLog refuses to serve: encryption key does not match this database.**
|
||||
At start the app checks that its key opens the stored data. If it does not,
|
||||
every API request answers `503` with `meta.errorCode`
|
||||
`encryption.key_mismatch`, `/api/health` answers `503` with
|
||||
`reason: "encryption_key_mismatch"`, and background jobs are not started.
|
||||
Restore the original key, point `DATABASE_URL` at the matching database, or
|
||||
start with an empty database; then restart.
|
||||
|
||||
## Backup and restore
|
||||
|
||||
Your database is the only stateful piece — back it up, and back up the
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
"label": "API token HMAC key",
|
||||
"description": "Generate with: openssl rand -hex 32"
|
||||
},
|
||||
{
|
||||
"name": "HEALTHLOG_PLATFORM",
|
||||
"label": "Platform hint",
|
||||
"description": "Opens the admin's encryption key backup step on the Portainer instructions.",
|
||||
"default": "portainer"
|
||||
},
|
||||
{
|
||||
"name": "SESSION_COOKIE_SECURE",
|
||||
"label": "Session cookie Secure flag",
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# HealthLog on TrueNAS SCALE
|
||||
|
||||
HealthLog runs on TrueNAS SCALE as a Docker app: one `app` container from
|
||||
`ghcr.io/mbombeck/healthlog` and one PostgreSQL 16 database. The app container
|
||||
is stateless; everything you care about lives in the database dataset and in
|
||||
one value you must keep yourself: the encryption key.
|
||||
|
||||
## What the app needs
|
||||
|
||||
| Setting | Value |
|
||||
| ------------ | ---------------------------------------------------------------------------------------- |
|
||||
| Image | `ghcr.io/mbombeck/healthlog`, tag `X.Y.Z` (amd64 and arm64) |
|
||||
| Port | `3000` (HTTP) |
|
||||
| User | runs as uid `1001`; no extra capabilities, `no-new-privileges` is fine |
|
||||
| Health check | `GET /api/health`, `200` when ready |
|
||||
| Start period | at least 60 s, with more retries than the image's 3 × 30 s: migrations run at every boot |
|
||||
| Database | PostgreSQL 16 (17 and later are not a drop-in), no extensions |
|
||||
| Volumes | none for the app; the database gets its own dataset |
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Required | Notes |
|
||||
| ----------------------- | -------- | ------------------------------------------------------------------------------------------- |
|
||||
| `DATABASE_URL` | yes | `postgresql://<user>:<password>@<host>:5432/<db>` |
|
||||
| `ENCRYPTION_KEY` | yes | 64 hex characters: `openssl rand -hex 32`. Keep a copy outside the NAS (see below). |
|
||||
| `API_TOKEN_HMAC_KEY` | yes | 64 hex characters, generated the same way. Changing it signs everyone out. |
|
||||
| `NEXT_PUBLIC_APP_URL` | yes | the address people open, for example `http://truenas.local:30180` |
|
||||
| `APP_URL` | yes | the same address |
|
||||
| `SESSION_COOKIE_SECURE` | no | `false` for a LAN install served over plain `http://`; leave unset behind an HTTPS proxy |
|
||||
| `HEALTHLOG_PLATFORM` | no | `truenas`: the admin's key backup step opens on the TrueNAS instructions |
|
||||
| `GEOLITE2_DIR` | no | a mounted directory of GeoLite2 `.mmdb` files, so sign-in locations are resolved on the NAS |
|
||||
|
||||
`HEALTHLOG_PROCESS_TYPE` stays unset (`all`): one container serves the web app
|
||||
and runs the background jobs.
|
||||
|
||||
## Plain HTTP on the LAN
|
||||
|
||||
Most NAS installs are reached over `http://`. Set `SESSION_COOKIE_SECURE=false`
|
||||
for that. If it is left at its default, the browser drops the sign-in cookie
|
||||
and the login page says so before you type a password: "This server only sets
|
||||
its sign-in cookie over https://".
|
||||
|
||||
## Back up your encryption key
|
||||
|
||||
HealthLog encrypts tokens, notes, documents and in-database backups with
|
||||
`ENCRYPTION_KEY`. The key is not stored in the database. If the app is deleted
|
||||
and reinstalled with a new key over the old database dataset, the data is
|
||||
still there but cannot be read.
|
||||
|
||||
1. Copy `ENCRYPTION_KEY` from the app's settings (Apps, HealthLog, Edit,
|
||||
Environment) into your password manager.
|
||||
2. Sign in as the admin and open Admin, Encryption. The step shows the key id
|
||||
and a fingerprint, the first 12 hex characters of SHA-256 over the key.
|
||||
Compare it with your copy:
|
||||
|
||||
```bash
|
||||
echo -n "<your key>" | xxd -r -p | sha256sum | cut -c1-12
|
||||
```
|
||||
|
||||
or paste the copy into "Check my copy" (it is compared and dropped, never
|
||||
stored or logged).
|
||||
|
||||
3. Confirm the backup. Until you do, admins see a reminder on the dashboard.
|
||||
After a key rotation the step comes back for the new key.
|
||||
|
||||
## When the key does not match the database
|
||||
|
||||
At every start HealthLog checks that its key opens the data already in the
|
||||
database. If it does not, it refuses to serve instead of failing on every
|
||||
encrypted value: pages show "HealthLog cannot open its data", API requests
|
||||
answer `503` with `meta.errorCode` `encryption.key_mismatch`, `/api/health`
|
||||
answers `503` with `reason: "encryption_key_mismatch"`, and no background jobs
|
||||
run. TrueNAS shows the app as unhealthy rather than crashed, so the reason
|
||||
stays visible.
|
||||
|
||||
Fix it one of three ways, then restart the app:
|
||||
|
||||
1. Put the original `ENCRYPTION_KEY` back.
|
||||
2. Point `DATABASE_URL` at the database that belongs to this key.
|
||||
3. Start fresh with an empty database. The old data and its backups need the
|
||||
old key.
|
||||
|
||||
## Updates
|
||||
|
||||
Pick the new tag, take a snapshot of the database dataset first, and update.
|
||||
Migrations run on start; the first start of a new install applies all of them,
|
||||
which is why the start period above is generous.
|
||||
@@ -121,6 +121,14 @@ Set `SESSION_COOKIE_SECURE=true` (or leave it unset) only when a TLS reverse
|
||||
proxy serves HealthLog over HTTPS. In that case also point `NEXT_PUBLIC_APP_URL`
|
||||
and `APP_URL` at the public `https://` URL.
|
||||
|
||||
## Back up your encryption key
|
||||
|
||||
Copy `ENCRYPTION_KEY` from the template into your password manager, then
|
||||
confirm it under Admin, Encryption (set `HEALTHLOG_PLATFORM=unraid` so the step
|
||||
opens on the Unraid instructions). A reinstall with a new key over the old
|
||||
database makes the data unreadable; HealthLog then refuses to serve and says
|
||||
so. See [Getting started](getting-started.md#back-up-your-encryption-key).
|
||||
|
||||
## Updates
|
||||
|
||||
Pin a release tag (`ghcr.io/mbombeck/healthlog:vX.Y.Z`) and bump deliberately,
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<Config Name="API_TOKEN_HMAC_KEY" Target="API_TOKEN_HMAC_KEY" Default="" Mode="" Description="HMAC key for API token hashing. Generate with: openssl rand -hex 32 (64-char hex)." Type="Variable" Display="always" Required="true" Mask="true"/>
|
||||
|
||||
<Config Name="SESSION_COOKIE_SECURE" Target="SESSION_COOKIE_SECURE" Default="false" Mode="" Description="Set to false for LAN / plain-HTTP installs (http://tower:3000) or login fails. Set to true only behind an HTTPS reverse proxy." Type="Variable" Display="always" Required="true" Mask="false">false</Config>
|
||||
<Config Name="HEALTHLOG_PLATFORM" Target="HEALTHLOG_PLATFORM" Default="unraid" Mode="" Description="Where this server is configured. Opens the admin's encryption key backup step on the Unraid instructions." Type="Variable" Display="advanced" Required="false" Mask="false">unraid</Config>
|
||||
|
||||
<Config Name="NEXT_PUBLIC_APP_URL" Target="NEXT_PUBLIC_APP_URL" Default="http://tower:3000" Mode="" Description="Public URL users reach HealthLog at. Use the LAN URL (e.g. http://tower:3000) or your HTTPS domain behind a reverse proxy." Type="Variable" Display="always" Required="true" Mask="false"/>
|
||||
|
||||
|
||||
Reference in new issue
Block a user