dorfteich/deploy/compose/.env.example
Claude Fable 5 20677ea247
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
Self-hosting findings: URL-safe password advice, operator-readable pre-seed errors (#324, #325)
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
2026-08-04 12:44:16 +02:00

171 lines
8.5 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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