# Petal — production environment for the parodia.dev VPS. # Copy to the stack directory as `.env` (docker-compose.yml reads it via # env_file) and fill in the model names. Values the image already fixes # (PORT, DATABASE_PATH, IMAGE_DIR, TTS_CACHE_DIR, TTS endpoints) are set in # docker-compose.yml, not here. # --- Routing ----------------------------------------------------------------- # Must match the DNS A record and the Traefik Host() rule. PETAL_HOST=petal.parodia.dev # Absolute origin the app knows itself by. Phase 16's OIDC redirect URI is # built from this, so it has to be the real public HTTPS origin. BASE_URL=https://petal.parodia.dev # The companion's bedtime nag and the night theme read the container clock. TZ=Europe/Lisbon # The container runs as this uid/gid so it can write the ./data bind mount. # Set both to the output of `id -u` / `id -g` for the account owning the stack # directory. Wrong values show up as "unable to open database file (14)". PETAL_UID=1001 PETAL_GID=1001 # --- Interim edge gate (delete when Phase 16 auth lands) --------------------- # Petal has no authentication of its own yet — StaticResolver hands every # request the same local user — so Traefik holds the door with basic auth until # the OIDC flow exists. user:bcrypt-hash, as produced by: # htpasswd -nbB petal 'your-password' # /api/health is deliberately exempt (its own router) so monitoring still works. PETAL_BASIC_AUTH= # --- LLM (millenia, over headscale) ------------------------------------------ # The only cross-VPN dependency. Petal degrades warmly when it's unreachable: # spell check, gloss, garden, search, export and read-aloud all keep working and # the status bar shows 小助手在休息 · Petal's helper is resting. # # 100.64.0.2 is millenia on the headscale network. vLLM must be bound to that # interface (NOT 0.0.0.0 — this host is public); see deploy/README.md. LLM_BACKEND=vllm LLM_ENDPOINT=http://100.64.0.2:8000 LLM_MODEL= LLM_CHAT_MODEL= # 30s is the local-network default. Over WAN + VPN, with the voice and # collocation passes sending a whole document, that truncates real work — the # request is a hard deadline on Complete, and a timeout surfaces as the same # warm 502 as an unreachable model. 90s leaves headroom without letting a # genuinely wedged backend hang the pass forever. LLM_TIMEOUT=90s # --- Read-aloud (Piper sidecars) --------------------------------------------- # Endpoints are wired in docker-compose.yml; these pick the voice each sidecar # loads. Changing one means recreating that container so it downloads the model. TTS_VOICE_EN=en_US-amy-medium TTS_VOICE_ZH=zh_CN-huayan-medium TTS_AUDIO_FORMAT=mp3 TTS_TIMEOUT=15s # --- Auth (Authentik OIDC) --------------------------------------------------- # Authentik already runs on this host. Set all three and Petal authenticates # for itself; leave any unset and it falls back to the single `local` user # (which on a public host means the Traefik basic-auth gate must stay). # # AUTHENTIK_URL is the provider's issuer, and the redirect URI to register in # Authentik is https://petal.parodia.dev/auth/callback. # AUTHENTIK_URL=https://auth.parodia.dev/application/o/petal/ # AUTHENTIK_CLIENT_ID=petal # AUTHENTIK_CLIENT_SECRET= # # Who may sign in: comma-separated subject ids and/or emails. Empty = anyone # Authentik authenticates, which is wider than this instance wants. # PETAL_ALLOWED_SUBS=