# Host-side bind mount paths — set to wherever you store Docker data DATA_DB_PATH=/your/host/path/db DATA_UPLOADS_PATH=/your/host/path/uploads # Required if using user management — use a long random string, keep it secret # Generate one: openssl rand -base64 48 JWT_SECRET=change-me-to-a-long-random-secret # Or mount it as a Docker/Swarm secret: # JWT_SECRET_FILE=/run/secrets/lifttrace_jwt_secret # Optional — At-rest encryption key for OIDC client secrets and wearable # OAuth tokens. Defaults to a key derived from JWT_SECRET, which means # rotating JWT_SECRET also invalidates every encrypted secret. Set # TOKEN_ENC_KEY explicitly if you want to rotate session tokens # independently of stored secrets. # Generate one: openssl rand -base64 48 # TOKEN_ENC_KEY=change-me-to-a-long-random-key # TOKEN_ENC_KEY_FILE=/run/secrets/lifttrace_token_enc_key # Optional — Lockout recovery token # Required to use the "Disable user management" recovery option on the login page # Without this, the recovery endpoint is disabled for safety # RECOVERY_TOKEN=my-secret-recovery-phrase # RECOVERY_TOKEN_FILE=/run/secrets/lifttrace_recovery_token # Optional — Mount the app at a path other than root (for reverse-proxy setups) # Example: BASE_URL=/lifttrace will serve the app at https://example.com/lifttrace/ # Default unset = served at root path. Configure your reverse proxy to pass the # path through *without* stripping it. # BASE_URL=/lifttrace # Optional — Log level (error | warn | info | debug) # Default: info # LOG_LEVEL=info # Optional — SMTP email (for password reset & user invites) # If set, these override whatever is configured in the Settings UI AND lock those fields for all users # SMTP_HOST=smtp.example.com # SMTP_PORT=587 # SMTP_SECURE=false # true for port 465 (SSL), false for STARTTLS # SMTP_USER=you@example.com # SMTP_PASS=your-password # SMTP_FROM=LiftTrace # SMTP_PASS_FILE=/run/secrets/lifttrace_smtp_pass # Optional — Trace AI (shared key for all users) # If set, AI calls are proxied through the server (key never reaches the browser) # and the provider/model/key fields are locked in Settings for all users. # Supports every provider the app supports — cloud (claude / openai / gemini) # and OpenAI-compatible local endpoints (Ollama, LM Studio, LocalAI, vLLM, # DeepSeek, Groq, etc.). Set AI_PROVIDER=oai-compat + AI_BASE_URL + AI_MODEL # to point at a private-network LLM the browser can't reach directly (e.g. # a Docker Compose sidecar on an internal network). # AI_PROVIDER=claude # claude | openai | gemini | oai-compat # AI_API_KEY=sk-ant-... # required for cloud providers; optional for oai-compat # AI_API_KEY_FILE=/run/secrets/lifttrace_ai_api_key # AI_MODEL=claude-haiku-4-5-20251001 # optional for cloud (defaults to provider's fast model); REQUIRED for oai-compat # AI_BASE_URL=http://ollama:11434 # REQUIRED when AI_PROVIDER=oai-compat; must be reachable from the server container # AI_ENABLED=true # optional, auto-enables Trace for all users # Optional — OIDC Single Sign-On (declared in env instead of the Settings UI) # # Single-provider shorthand — `OIDC_*` is an alias for `OIDC_PROVIDER_1_*`: # OIDC_ISSUER=https://auth.example.com # OIDC_CLIENT_ID=lifttrace # OIDC_CLIENT_SECRET=... # OIDC_DISPLAY_NAME=Authentik # OIDC_REDIRECT_URIS=https://lifttrace.example.com/api/auth/oidc/callback/1 # comma-separated for multi # OIDC_SCOPE=openid profile email # OIDC_TOKEN_AUTH_METHOD=client_secret_post # or client_secret_basic | none # OIDC_ADMIN_GROUP_CLAIM=groups # OIDC_ADMIN_GROUP_VALUE=LiftTraceAdmins # OIDC_AUTO_LINK=1 # link verified-email to existing users (default 1) # OIDC_AUTO_REGISTER=0 # blanket signup on first SSO login (default 0) # OIDC_IS_ACTIVE=1 # # Multi-provider — use the numbered prefix: # OIDC_PROVIDER_2_ISSUER=https://other-idp.example.com # OIDC_PROVIDER_2_CLIENT_ID=... # OIDC_PROVIDER_2_CLIENT_SECRET=... # OIDC_PROVIDER_2_DISPLAY_NAME=Keycloak # # Env-defined providers show with a lock badge in Settings → Admin → OIDC # providers and are read-only. Edit via .env / docker-compose / k8s # secrets — UI mutations on env-defined providers are refused server-side.