Voysse

Configuration

Complete environment variable reference for all three services.

Complete environment variable reference for all three services. For install, secrets rotation, HTTPS and production guidance see Self-hosting; for a first-run walkthrough see Getting started.

Contents

The single-origin gateway model

The Docker stack serves the whole app from one origin through a Caddy gateway (proxy service, docker/Caddyfile): the browser calls the API with a relative /api/... path, and the gateway routes /api/* to the backend and everything else to the frontend. This is why NEXT_PUBLIC_API_URL is empty by default (apps/web/lib/api.ts falls back to "") — the frontend and API share an origin, so no absolute API URL is needed in the browser. Set NEXT_PUBLIC_API_URL only when the frontend must call an API on a genuinely separate origin; it's baked in at build time, so changing it means rebuilding the web image (or re-running npm run build outside Docker).

Docker / gateway

./scripts/generate-docker-env.sh fills the secrets below into .env.docker (gitignored); to set values by hand instead, copy .env.docker.example to .env.docker. Host-port and image variables come from the Makefile / docker-compose.yml and can also be overridden inline (e.g. API_PORT=8001 make up).

VariableDefaultPurpose
POSTGRES_DBopenvoissMain PostgreSQL database name.
POSTGRES_USERopenvoissPostgreSQL role used by the api service.
POSTGRES_PASSWORDrandom (generated)Password for that role.
POSTGRES_TEST_DBopenvoiss_testIsolated database created for pytest; wired into TEST_DATABASE_URL for the api container.
SECRET_KEYrandom (generated)Signs agency and portal session JWTs.
ENCRYPTION_KEYrandom (generated)Encrypts provider API keys and WhatsApp session state at rest. ⚠️ Must never change once secrets are stored — see Self-hosting → Secure your install.
WHATSAPP_BRIDGE_TOKENrandom (generated)Authenticates backend↔bridge calls.
FRONTEND_URLhttp://localhost:3000CORS origin allowed by the backend; only needed when serving the API on a separate origin.
ACCESS_TOKEN_MINUTES10080 (7 days)Session cookie / JWT lifetime, in minutes.
COOKIE_SECUREfalseSet true behind HTTPS so the session cookie is only sent over TLS.
COOKIE_SAMESITElaxnone when the frontend and API are on different sites (requires COOKIE_SECURE=true).
WHATSAPP_LOG_LEVELsilentBridge log verbosity (pino); silent avoids logging sensitive data.
API_PORT8000Host port for the API (also serves /docs).
WEB_PORT3000Host port for the gateway — the app's URL.
DB_PORT5432Host port for PostgreSQL.
BIND_HOST127.0.0.1Bind address for the ports above: 127.0.0.1 (local only) or 0.0.0.0 (expose on a server).
OPENVOISS_VERSIONlatestImage tag pulled by make pull, e.g. v1.2.3.
OPENVOISS_IMAGE_PREFIXghcr.io/kanazawa-dev/openvoissRegistry/prefix used by make pull, to pull from a self-hosted registry instead.

docker-compose.yml sets several backend/frontend/bridge variables for you automatically (DATABASE_URL, TEST_DATABASE_URL, BACKEND_URL, WHATSAPP_BRIDGE_URL, STORAGE_DIR, BACKEND_INTERNAL_URL, WHATSAPP_BRIDGE_HOST, WHATSAPP_BRIDGE_PORT) by wiring the containers together on the private Compose network — you don't set these yourself in .env.docker. They're listed in the tables below because they're real per-service variables you do set by hand when running without Docker.

Backend (API)

Source of truth: apps/api/app/config.py (a Pydantic Settings class, one field per row below). Each variable is the field name upper-cased (pydantic-settings matches env vars case-insensitively); in Docker they're read from .env.docker, outside Docker from apps/api/.env (or the shared root .env — env_file checks the repo root first, then apps/api/.env).

VariableDefaultPurpose
APP_NAMEVoysse APIDefined in Settings but not currently read anywhere else in the codebase (the FastAPI app title is hardcoded in app/main.py).
DATABASE_URLpostgresql+psycopg://openvoiss:openvoiss@localhost:5432/openvoissSQLAlchemy connection string for the main database.
TEST_DATABASE_URLsee apps/api/tests/conftest.pyNot a Settings field — read directly by conftest.py to point pytest at openvoiss_test instead of the dev database.
SECRET_KEYdev-local-change-this-key-pleaseSigns agency/portal session JWTs. Change for any real deployment.
ENCRYPTION_KEYdev-local-change-this-key-tooEncrypts provider API keys and WhatsApp session state. ⚠️ Never change once secrets exist — see Self-hosting.
FRONTEND_URLhttp://localhost:3000CORS-allowed origin.
ACCESS_TOKEN_MINUTES10080Session lifetime, in minutes.
COOKIE_SECUREfalsetrue behind HTTPS so the session cookie is TLS-only.
COOKIE_SAMESITElaxnone when frontend and API are on different sites (needs COOKIE_SECURE=true).
RATE_LIMIT_ENABLEDtruePer-client-IP throttling on public/unauthenticated endpoints (auth, portal login, widget messages). Disable only for tests or when a proxy in front already rate-limits.
TOOLS_ALLOW_PRIVATE_URLSfalseSSRF guard for agent HTTP tools: by default a tool URL resolving to a private/loopback address is rejected. Enable only if your deployment needs tools to reach internal services.
STORAGE_DIRapps/api/storageDefined in Settings (Docker points it at /app/backend/storage, a mounted volume) but not currently read elsewhere in the codebase — uploads (agency logos) and knowledge PDFs are stored in PostgreSQL, not on disk.
BACKEND_URLhttp://localhost:8000Defined in Settings (Docker sets it to http://api:8000) but not currently read elsewhere in the codebase.
WHATSAPP_BRIDGE_URLhttp://localhost:3101Base URL the backend uses to call the WhatsApp bridge (QR requests, session actions).
WHATSAPP_BRIDGE_TOKENdev-local-change-this-bridge-tokenMust match the bridge's own WHATSAPP_BRIDGE_TOKEN.
META_GRAPH_BASE_URLhttps://graph.facebook.com/v23.0Meta Graph API root used by the WhatsApp Cloud API channel; override to point at a mock server in tests.

Frontend (Web)

Source: apps/web/lib/api.ts, apps/web/proxy.ts, apps/web/components/app-shell.tsx and apps/web/components/app-sidebar.tsx. Every NEXT_PUBLIC_* variable is baked in at build time (Next.js inlines it into the client bundle), so changing one means rebuilding — docker-compose.yml passes them as Docker build args for the web service.

VariableDefaultPurpose
NEXT_PUBLIC_API_URLemptyLeft empty so the browser calls the API through the gateway with a relative /api path (single-origin model above). Set only to point the frontend at an API on a separate origin.
BACKEND_INTERNAL_URLhttp://api:8000 (Docker)Server-side only, used by proxy.ts to call the API directly when resolving a verified custom portal domain. Not NEXT_PUBLIC_* — never reaches the browser.
NEXT_PUBLIC_EXTRA_NAVemptyOptional extra sidebar entries as comma-separated label|href|icon triples, so a deployment can add pages without patching the shell.
NEXT_PUBLIC_PUBLIC_PATHSemptyOptional comma-separated path prefixes served without a session, for the same reason.

WhatsApp bridge

Source: apps/whatsapp/src/api.ts, apps/whatsapp/src/index.ts and apps/whatsapp/src/manager.ts.

VariableDefaultPurpose
BACKEND_URLhttp://localhost:8000Where the bridge calls the backend's inbound WhatsApp endpoints (Docker sets http://api:8000).
WHATSAPP_BRIDGE_TOKENdev-local-change-this-bridge-tokenMust match the backend's value.
WHATSAPP_BRIDGE_PORT3101Port the bridge listens on.
WHATSAPP_BRIDGE_HOST127.0.0.1Bind address; Docker sets 0.0.0.0 since the bridge is only reachable from other containers (not exposed on the host).
WHATSAPP_LOG_LEVELsilentLog verbosity (pino).

Run without Docker

Each service reads its variables the same way; you just supply an env file per service instead of .env.docker. See Self-hosting → Run without Docker for the exact install and start commands (cp .env.example .env, then set at least SECRET_KEY and ENCRYPTION_KEY before running alembic upgrade head and uvicorn, npm run dev, and npm run start for the three services).

On this page