diff --git a/CHANGELOG.md b/CHANGELOG.md index 08d2c20cd..c59deeb8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,36 @@ # Changelog +## [1.5.2] — 2026-05-26 — Plumb SESSION_COOKIE_SECURE through docker-compose + +v1.5.1 added a `SESSION_COOKIE_SECURE` env var so plain-HTTP self-hosts can drop the cookie's `Secure` flag. The Node helper read it correctly and the unit tests passed, but a self-hoster following the documented `.env` workaround reported that `docker compose exec app env | grep SESSION_COOKIE` came back empty — the value was set in `.env`, set in the helper, but never reached the running container. + +Root cause is the way the bundled `docker-compose.yml` passes env vars to the `app` service: it lists each one explicitly under `environment:` rather than mounting the `.env` file wholesale. Variables not on that whitelist are read by `docker compose` for `${VAR}` substitution but never propagated to the container's process env. `SESSION_COOKIE_SECURE` wasn't on the list, so setting it in `.env` was a silent no-op. + +### Fixed + +- `docker-compose.yml` now lists `SESSION_COOKIE_SECURE: "${SESSION_COOKIE_SECURE:-}"` under the `app` service's `environment:` block. Defaults to empty (so the helper falls back to `NODE_ENV === "production"`, the pre-v1.5.1 behaviour); setting it to `false` in `.env` now actually reaches the Node process. + +### Self-hoster recipe (full, now end-to-end working) + +```bash +git pull # picks up the new compose file +docker compose pull # picks up the new image (no-op if already on :latest) +echo 'SESSION_COOKIE_SECURE=false' >> .env +docker compose up -d --force-recreate +``` + +Verify with: + +```bash +docker compose exec app env | grep SESSION_COOKIE +# SESSION_COOKIE_SECURE=false + +curl http://10.x.x.x:3000/api/version +# {"data":{"version":"1.5.2",...}} +``` + +Then log in over plain HTTP from a non-localhost browser — the session cookie no longer carries `Secure`, the browser keeps it, and the round-trip completes. + ## [1.5.1] — 2026-05-26 — Self-hosting opt-out for the session-cookie `Secure` flag A self-hoster running HealthLog on a LAN address (`http://10.x.x.x:3000`) over plain HTTP reported a silent login failure: the `/api/auth/login` POST returned 200 with a `Set-Cookie` header on the response, but the very next `/api/auth/me` request came back 401 and the page reloaded to the login screen. Root cause is the modern browser behaviour around `Secure`-flagged cookies — every cookie the app issues in `NODE_ENV=production` carries `Secure`, and on a plain-HTTP origin that is not `localhost` / `127.0.0.1` / `::1`, the browser silently drops the cookie before sending the next request. The default-Docker image runs `NODE_ENV=production`, so any operator browsing from a different host than the one running `docker compose up` (NAS / homelab / VPS / Tailscale + Magic-DNS) used to hit the dead-end. diff --git a/docker-compose.yml b/docker-compose.yml index 62e3085a3..edcfaa8b6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,6 +26,13 @@ services: API_TOKEN_HMAC_KEY: "${API_TOKEN_HMAC_KEY}" NEXT_PUBLIC_APP_URL: "${NEXT_PUBLIC_APP_URL:-http://localhost:3000}" APP_URL: "${APP_URL:-http://localhost:3000}" + # v1.5.1 session-cookie Secure-flag opt-out. Forwarded explicitly so + # an operator setting SESSION_COOKIE_SECURE=false in .env actually + # reaches the Node process (the compose `environment:` block is a + # whitelist — vars not listed here don't propagate from .env into + # the container, even though docker-compose reads .env for + # `${VAR}` substitution at compose-up time). + SESSION_COOKIE_SECURE: "${SESSION_COOKIE_SECURE:-}" # all = bundle web + worker in this container (default, single-host) # web = serve HTTP only; pair with a separate app-worker service HEALTHLOG_PROCESS_TYPE: "${HEALTHLOG_PROCESS_TYPE:-all}" diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index 23fb7d36d..5dfb0bb48 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: HealthLog API - version: 1.5.1 + version: 1.5.2 description: >- Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest. diff --git a/package.json b/package.json index 18c151576..07d671f7f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "healthlog", - "version": "1.5.1", + "version": "1.5.2", "description": "Self-hosted personal-health-tracking PWA with Withings integration, AI insights, and doctor-report PDF export.", "license": "AGPL-3.0-only", "homepage": "https://healthlog.dev",