# Configuration Scribe reads its configuration from environment variables. Most settings people change day to day (registration, SMTP, retrieval thresholds, backups, forge connections) live in **Settings** in the web UI instead. Any variable marked *secret* can also be read from a file: set `_FILE` to the path, for example a Docker secret at `/run/secrets/scribe_key`. ## Environment variables ### Core | Variable | Default | Description | |----------|---------|-------------| | `DATABASE_URL` *(secret)* | `postgresql+asyncpg://scribe:scribe@localhost:5432/scribe` | PostgreSQL connection string, using the `asyncpg` driver | | `SECRET_KEY` *(secret)* | `dev-secret-change-me` | Signs sessions and seals stored credentials. Set it before first use and keep it (see below) | | `BASE_URL` | `http://localhost:5000` | Public URL, used in email links and OIDC redirects | | `SECURE_COOKIES` | `false` | `true` when Scribe is served over HTTPS | | `TRUST_PROXY_HEADERS` | `false` | `true` behind a reverse proxy, to read the client IP from `X-Forwarded-For` / `X-Real-IP` | | `LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING` or `ERROR` | | `LOG_RETENTION_DAYS` | `90` | Days of app logs to keep | | `FASTEMBED_CACHE_DIR` | `/data/fastembed-cache` | Where the embedding model is stored after its first download | ### Sign-in | Variable | Default | Description | |----------|---------|-------------| | `LOCAL_AUTH_ENABLED` | `true` | `false` turns off username/password login, leaving SSO only | | `OIDC_ISSUER` | — | OIDC issuer URL | | `OIDC_CLIENT_ID` | — | OIDC client ID | | `OIDC_CLIENT_SECRET` *(secret)* | — | OIDC client secret | | `OIDC_SCOPES` | `openid profile email` | Scopes to request | SSO turns on when the issuer, client ID and secret are all set. See [SSO / OAuth](sso-oauth.md). ### Email Admins can set SMTP in **Settings**; these are the defaults until they do. | Variable | Default | |----------|---------| | `SMTP_HOST` | — | | `SMTP_PORT` | `587` | | `SMTP_USERNAME` | — | | `SMTP_PASSWORD` *(secret)* | — | | `SMTP_FROM_ADDRESS` | — | | `SMTP_FROM_NAME` | `Fabled Scribe` | | `SMTP_USE_TLS` | `true` | ### Integrations | Variable | Default | Description | |----------|---------|-------------| | `PLUGIN_MARKETPLACE_URL` | this repo's git URL | The git URL shown in the plugin install command under Settings → MCP Access. An admin can override it in Settings | | `FORGE_KIND`, `FORGE_BASE_URL`, `FORGE_TOKEN` *(secret)* | — | A git forge connection for admins' projects, so a token can live in a Docker secret. Each user can add their own under Settings → Integrations; a stored connection for the same host wins | | `FORGE_WEBHOOK_SECRET` *(secret)* | — | Verifies push webhooks from the forge | | `SEARXNG_URL` | — | A SearXNG instance, listed as the web-search backend under Settings → Integrations | ## Running it ### Quick start [`docker-compose.quickstart.yml`](../docker-compose.quickstart.yml) runs the published image with its own database: ```bash SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_hex(32))') \ docker compose -f docker-compose.quickstart.yml up -d ``` Open `http://localhost:5000`. The first account registered becomes the admin; after that, registration stays closed until an admin opens it in Settings or sends an invite. ### From source ```bash cp .env.example .env # then set SECRET_KEY docker compose up --build ``` ### Docker Swarm [`docker-compose.prod.yml`](../docker-compose.prod.yml) is a stack file: the app and database on a private overlay network, with `SECURE_COOKIES` and `TRUST_PROXY_HEADERS` on. Provide `DB_PASSWORD` and `SECRET_KEY` in the environment: ```bash DB_PASSWORD=... SECRET_KEY=... docker stack deploy -c docker-compose.prod.yml scribe ``` The shipped files leave out healthchecks and restart policies on purpose. The app waits for its database on startup, and the orchestrator's defaults restart it if it ever exits. ### Volumes - **Database** (`pgdata`): everything Scribe stores. - **App data** (`/data`): the embedding model cache and diagnostics. Losing it costs a re-download, nothing else. Back up the database with **Settings → Data → Scheduled backups** ([Backups](backups.md)). ## Behind a reverse proxy Scribe doesn't terminate TLS. Put it behind Nginx, Traefik or Caddy, forward to port 5000, and keep port 5000 off the internet. Set `SECURE_COOKIES=true`, `TRUST_PROXY_HEADERS=true` and `BASE_URL`. ```nginx location / { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # MCP responses can stream. proxy_buffering off; proxy_read_timeout 600s; } ``` With `TRUST_PROXY_HEADERS=true`, make sure the proxy replaces any `X-Forwarded-For` the client sends. ## Security checklist - **Set a strong `SECRET_KEY`, and keep it.** Forge tokens and the backup destination's S3 secret are sealed under a key derived from it, so a copy of the database alone can't read them. If the key changes (say, a restore onto an instance with a different key), Settings marks those credentials and asks for them again; nothing else breaks. The app logs a warning at startup while the default key is in use, and refuses to start with it when `SECURE_COOKIES=true`. - **`SECURE_COOKIES=true`** whenever Scribe is served over HTTPS. - **Registration** is open only for the first account. Invite people, or open it briefly from Settings. - **Signing everyone else out**: changing a password ends that user's other sessions; Settings → Account has a button for it too. - **API keys** are per user, shown once, and can be read-only. Revoke any you no longer use under Settings → MCP Access.