Some checks failed
CI / Lint, typecheck, test (pull_request) Successful in 7m58s
CI / Build container images (pull_request) Successful in 1m11s
CI / Auth e2e pack (pull_request) Successful in 9m12s
CI / Import/export fidelity gate (pull_request) Successful in 59s
CD / Deploy to Test (push) Blocked by required conditions
CD / Smoke tests against Test (push) Blocked by required conditions
CI / Auth e2e pack (push) Blocked by required conditions
CI / Import/export fidelity gate (push) Blocked by required conditions
CI / Build container images (push) Blocked by required conditions
CD / Build and push images (push) Has been cancelled
CI / Lint, typecheck, test (push) Has been cancelled
CD / Promote to Int (push) Blocked by required conditions
Two findings from Stefan's manual clean install per the guide, both ending in an api restart loop that was hard to diagnose: - #324: the guide recommended `openssl rand -base64 32` for POSTGRES_PASSWORD, but the compose interpolates the password unescaped into DATABASE_URL — base64's `/`, `+`, `=` break the URL. Misleadingly, db stays healthy (it gets the password as a plain env var) while api/collab/backup crash. Guide and .env.example now recommend `openssl rand -hex 24` for both secrets and say why; Troubleshooting gained the symptom line. - #325: SETUP_ADMIN_PASSWORD's minimum (10 chars, packages/shared/src/auth.ts) was undocumented, and a violation crashed the boot with a raw ZodError naming schema fields and i18n keys. Failing the boot stays — deliberately, no half-seeded instance — but preseedFromEnv now translates validation errors into operator terms ("Pre-seeding failed: SETUP_ADMIN_PASSWORD must be at least 10 characters. Fix .env and recreate the api container."). Documented in the guide's first-run section, .env.example, and Troubleshooting; new test pins the message and that nothing is half-seeded afterwards. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017aviRTgWCcAHUh1SBoxf6P
171 lines
8.5 KiB
Plaintext
171 lines
8.5 KiB
Plaintext
# Dorfteich stage configuration. Copy to `.env` (mode 600, never in git)
|
||
# next to docker-compose.yml and adjust the values.
|
||
|
||
# --- required ---------------------------------------------------------------
|
||
# PostgreSQL password for the `dorfteich` database user. URL-SAFE
|
||
# characters only (generate with `openssl rand -hex 24`): the compose file
|
||
# interpolates it into DATABASE_URL unescaped, so base64's `/`, `+`, `=`
|
||
# break the URL — db stays healthy while api/collab/backup restart-loop.
|
||
POSTGRES_PASSWORD=change-me
|
||
|
||
# ROOT key of the token key hierarchy (ADR 0020, issue #188): every token
|
||
# purpose (collaboration tokens, digest unsubscribe links) derives its own
|
||
# HKDF subkey from this value — nothing signs with it directly. The api and
|
||
# collab services share this one value; use a long random string
|
||
# (e.g. `openssl rand -hex 24`). Min length 16. Rotating it rotates all
|
||
# derived keys at once and invalidates outstanding tokens.
|
||
COLLAB_TOKEN_SECRET=change-me-to-a-long-random-string
|
||
|
||
# --- images -----------------------------------------------------------------
|
||
# Image name prefix. Stages pull from the Gitea registry, e.g.
|
||
# gitea.101010.cloud/stwaidele/dorfteich — local builds use the default.
|
||
IMAGE_PREFIX=dorfteich
|
||
# Image tag to run: a git SHA, `test`, `int`, or a release tag like v1.2.0.
|
||
TAG=latest
|
||
# Registry prefix for THIRD-PARTY images (postgres, pandoc, gotenberg,
|
||
# caddy) — for airgapped sites pulling from an internal mirror
|
||
# (issue #218, ADR 0024). Must end with a slash, e.g.
|
||
# `registry.example.gov/mirror/`. Empty = public registries. Own images
|
||
# are covered by IMAGE_PREFIX above, which may equally carry a registry.
|
||
REGISTRY_PREFIX=
|
||
|
||
# --- ports (localhost only; the host reverse proxy routes to these) ---------
|
||
# Suggested per stage on the shared host (ONE): test 8100/8101/8102,
|
||
# int 8110/8111/8112, prod 8120/8121/8122 (web/api/collab).
|
||
WEB_PORT=8100
|
||
API_PORT=8101
|
||
# collab (Hocuspocus) WebSocket server; the proxy routes /collab here.
|
||
COLLAB_PORT=8102
|
||
|
||
# --- behavior ----------------------------------------------------------------
|
||
# pino log level: fatal|error|warn|info|debug|trace
|
||
LOG_LEVEL=info
|
||
|
||
# Session bounds in hours (issue #190). ABSOLUTE caps the total session
|
||
# lifetime from login (also the cookie maxAge) — activity never extends it.
|
||
# IDLE ends sessions unused for that long; activity renews it, enforced
|
||
# server-side. Unset = defaults: 168 (7 days) absolute, 72 (3 days) idle.
|
||
# VS-NfD reference operation (hardening guide): 12 absolute, 1 idle.
|
||
#SESSION_ABSOLUTE_HOURS=168
|
||
#SESSION_IDLE_HOURS=72
|
||
|
||
# Compose project name; set per stage (dorfteich-test, dorfteich-int, …).
|
||
COMPOSE_PROJECT_NAME=dorfteich
|
||
|
||
# --- public URL + mail --------------------------------------------------------
|
||
# Public base URL of the stage (scheme + host). E-mail links and the CSRF
|
||
# origin check are derived from it — it must match what browsers use.
|
||
APP_BASE_URL=https://wiki.example.com
|
||
|
||
# SMTP relay for outgoing mail (verification, password reset). Optional:
|
||
# leave everything unset and configure the relay in the browser during the
|
||
# first-run setup wizard instead (stored on the `secrets` volume, issue #80).
|
||
# Values set here always win over wizard-stored ones.
|
||
SMTP_HOST=mail.example.com
|
||
SMTP_PORT=465
|
||
SMTP_SECURE=true
|
||
SMTP_USER=wiki@example.com
|
||
SMTP_PASS=change-me
|
||
SMTP_FROM=Dorfteich <wiki@example.com>
|
||
|
||
# --- optional TLS ingress (`caddy` profile, issue #88) -------------------------
|
||
# Only when you have no reverse proxy of your own: start with
|
||
# `docker compose --profile caddy up -d`. Caddy terminates TLS for DOMAIN
|
||
# via Let's Encrypt (80+443 must be reachable from the internet; keep
|
||
# APP_BASE_URL=https://<DOMAIN> in sync). The `localhost` default issues
|
||
# an internal-CA certificate instead — good for smoke tests only.
|
||
#DOMAIN=wiki.example.com
|
||
# Published ports; change only when 80/443 are taken on the host.
|
||
#CADDY_HTTP_PORT=80
|
||
#CADDY_HTTPS_PORT=443
|
||
|
||
# --- external authentication (issues #214–#216, ADR 0021) ---------------------
|
||
# Deploy-level on purpose — a Site Admin cannot change these. All unset =
|
||
# local username/password login only. Full reference:
|
||
# docs/architecture/security.md §External authentication.
|
||
# OIDC (Authorization Code + PKCE) is enabled iff ISSUER + CLIENT_ID are set;
|
||
# CLIENT_SECRET stays empty for a public client. Redirect URI to register at
|
||
# the IdP: $APP_BASE_URL/api/v1/auth/oidc/callback
|
||
#OIDC_ISSUER=https://idp.example.com/realms/example
|
||
#OIDC_CLIENT_ID=dorfteich-web
|
||
#OIDC_CLIENT_SECRET=
|
||
#OIDC_SCOPES=openid profile email
|
||
#OIDC_PROVIDER_LABEL=Single Sign-On
|
||
# Hard switch (#216): false turns EVERY local credential flow off (404) —
|
||
# sign-in only via OIDC or the trusted proxy. Complete the first-run setup
|
||
# BEFORE flipping it.
|
||
#AUTH_LOCAL_ENABLED=false
|
||
# Perimeter authentication (#215): identity from a proxy header, honoured
|
||
# only when the TCP peer is on the allowlist; the proxy MUST strip the
|
||
# header from incoming traffic. Unset = feature off, the header is inert.
|
||
#AUTH_PROXY_HEADER=X-Auth-User
|
||
#AUTH_PROXY_TRUSTED_PEERS=10.0.0.5
|
||
#AUTH_PROXY_MAP=username
|
||
#AUTH_PROXY_MODE=plain
|
||
#AUTH_PROXY_DN_ATTRIBUTE=CN
|
||
|
||
# --- backups (ADR 0015, issue #83) --------------------------------------------
|
||
# The backup sidecar dumps the database and archives the data volumes
|
||
# (uploads, plugins, custom fonts, branding) nightly onto the `backups`
|
||
# volume; restore via deploy/backup/restore.sh <backup-id>. All values
|
||
# optional.
|
||
# Daily run time HH:MM in TZ (default 03:00; set TZ for stage-local time,
|
||
# e.g. TZ=Europe/Berlin — unset means UTC).
|
||
#TZ=Europe/Berlin
|
||
#BACKUP_TIME=03:00
|
||
# Local retention in days: 30 (default) for Prod, 7 for Test/Int (ADR 0015).
|
||
# A Site Admin can override this in the admin UI (issue #103) — the saved
|
||
# setting then wins over this value.
|
||
#BACKUP_RETENTION_DAYS=30
|
||
# Off-host copies to a Nextcloud (issue #103) are configured entirely in the
|
||
# admin UI (Admin -> System -> Backups) — no env values needed here.
|
||
# Failure alert: recipient (unset = no mail, failures only in the logs and
|
||
# status.json), mail language (de|en), and the label used in the subject
|
||
# (defaults to the compose project name).
|
||
#BACKUP_MAIL_TO=ops@example.com
|
||
#BACKUP_MAIL_LOCALE=en
|
||
#BACKUP_INSTANCE_LABEL=dorfteich-test
|
||
# Deploy-level allowlist of permissible backup destination HOSTS (issue
|
||
# #192, ADR 0026), comma-separated — e.g. "cloud.example.org,172.30.1.10".
|
||
# EMPTY (the default) DISABLES every remote target, the admin-configured
|
||
# WebDAV/Nextcloud upload and the rsync mirror alike; backups then stay
|
||
# local only (the VS-NfD reference configuration). BREAKING: existing
|
||
# deployments with a remote target must list its host here, or uploads and
|
||
# mirror stop. Deploy-level on purpose: Site-Admins cannot widen it.
|
||
#BACKUP_ALLOWED_TARGETS=cloud.example.org,172.30.1.10
|
||
|
||
# VS-NfD hardening-profile mode (issue #243, ADR 0027): how the application
|
||
# treats configuration that violates the reference profile of
|
||
# docs/vs-nfd/50-haertungsleitfaden.md. off (default) = VS-NfD is not a
|
||
# topic, no marking anywhere; marked = violations are marked in the admin
|
||
# UI; hidden = violating options disappear (the hiding is marked);
|
||
# enforced = violating writes are rejected server-side. The treatments
|
||
# roll out with #244–#246; until then every non-off mode shows the profile
|
||
# card in the admin settings. Deploy-level on purpose: Site-Admins cannot
|
||
# widen it.
|
||
#VS_NFD_MODE=marked
|
||
|
||
# Optional rsync mirror of the backup sets to a private host (issue #84):
|
||
# rsync-over-ssh target plus the private key file INSIDE the container —
|
||
# put the key on the secrets volume (docker compose cp), never in the repo.
|
||
# Full setup walkthrough: deploy/backup-basel.md. Unset = no mirror.
|
||
#BACKUP_MIRROR_TARGET=dorfteich-backup@172.30.1.10:/home/RAID/BACKUPS/dorfteich-prod/
|
||
#BACKUP_MIRROR_SSH_KEY=/data/secrets/backup_mirror_ed25519
|
||
#BACKUP_MIRROR_SSH_PORT=22
|
||
|
||
# --- first-run setup (optional pre-seeding, issue #80) ------------------------
|
||
# A fresh (empty) database makes the instance require the browser setup
|
||
# wizard. Automated deploys can skip it entirely by pre-seeding the Site
|
||
# Admin here; the wizard then completes and locks itself at first boot.
|
||
# All three SETUP_ADMIN_* values are required for pre-seeding to trigger.
|
||
# The wizard's validation applies: the password needs at least 10
|
||
# characters — a violation fails the boot with a message naming the
|
||
# variable (deliberate: no half-seeded instance).
|
||
#SETUP_ADMIN_USERNAME=admin
|
||
#SETUP_ADMIN_EMAIL=admin@example.com
|
||
#SETUP_ADMIN_PASSWORD=change-me-please
|
||
#SETUP_ADMIN_DISPLAY_NAME=Admin
|
||
#SETUP_INSTANCE_NAME=Dorfteich
|
||
#SETUP_DEFAULT_LOCALE=en
|
||
#SETUP_REGISTRATION_MODE=open
|