fix(env): the documented Compose deploy could not boot
All checks were successful
PR Checks / client-build (pull_request) Successful in 30s
PR Checks / bot-tests (pull_request) Successful in 31s
PR Checks / server-tests (pull_request) Successful in 2m32s

`.env.example` — the file docker-compose.yml actually reads — never listed
SECRET_ENC_KEY. `utils/secretBox.js` resolves the key at require time and throws
`SECRET_ENC_KEY must be set in production`, so following README Option A exactly
produces a container that crash-loops before it ever listens.

It was easy to miss because the variable IS documented in two places that a
Compose operator never opens: `server/.env.example`, which is what local
development copies, and the README's environment-variable reference table. Only
the file the deployment reads was missing it.

Reproduced against the published image with a clean `cp .env.example .env`, then
verified the fix the same way: fill in the values the README names and
`docker compose up -d` reaches `listening on http://0.0.0.0:3000` and
`/api/health` → `{"status":"ok"}`.

- `.env.example` gains SECRET_ENC_KEY, beside JWT_SECRET, with what it encrypts,
  that production refuses to start without it, and that changing it later
  orphans every stored secret rather than re-encrypting them.
- README's Option A "set at least" list gains SECRET_ENC_KEY and
  BOT_INTERNAL_KEY. Both are refused-at-boot in production, and BOT_INTERNAL_KEY
  is required even on a deployment that runs no bot, which is exactly the case
  the list omitted.

Found while writing the runicgateway.com installation docs, whose quickstart is
checked against this file on every build.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-24 11:19:49 -05:00
parent 0f96a372cf
commit c43e092248
2 changed files with 20 additions and 0 deletions

View File

@@ -216,7 +216,12 @@ cp .env.example .env
# Edit .env and set at least:
# DB_PASSWORD, DB_ROOT_PASSWORD (any strong values)
# JWT_SECRET (a long random string)
# SECRET_ENC_KEY (a different long random string)
# BOT_INTERNAL_KEY (a third one, 16+ chars — even with no bot)
# ADMIN_USERNAME, ADMIN_PASSWORD (your first admin login)
#
# SECRET_ENC_KEY and BOT_INTERNAL_KEY are not optional in production: the app
# refuses to start without them, so the container crash-loops before it listens.
docker compose pull && docker compose up -d # IMAGE_TAG defaults to `latest`
# pin a specific build (reproducible deploy / rollback):