Skip to content
ThinkWatch
Start typing to search the docs.
EN
77 Get started

ThinkWatch Configuration Reference#

This document provides a complete reference for all configuration options in ThinkWatch. Configuration is managed through a combination of environment variables (for infrastructure and secrets) and database-backed dynamic settings (configurable via the admin Web UI).


Environment Variables#

Database#

DATABASE_URL#

PropertyValue
RequiredYes
Default
Examplepostgres://thinkwatch:password@localhost:5432/thinkwatch

PostgreSQL connection string. ThinkWatch requires PostgreSQL 15 or later.

Security notes:

  • In production, use sslmode=require to enforce encrypted connections: postgres://user:pass@host:5432/db?sslmode=require
  • Avoid embedding passwords in URLs checked into version control. Use a secrets manager.
  • The database user needs permissions to create tables (for migrations) or should have migrations applied separately.

REDIS_URL#

PropertyValue
RequiredYes
Default
Exampleredis://localhost:6379

Redis connection string. Used for rate limiting, OIDC state/nonce storage, and session management.

Security notes:

  • In production, enable Redis authentication: redis://:yourpassword@host:6379
  • For TLS-enabled Redis, use the rediss:// scheme: rediss://:password@host:6380

Cryptography#

JWT_SECRET#

PropertyValue
RequiredYes
Default
Examplea3f8c1e0b9d74... (64-character hex string)

Shared secret used for HS256 JWT signing and verification. Must be at least 32 characters long, and at least 256 bits (32 bytes / 64 hex characters) is recommended for adequate security. At startup, ThinkWatch performs an entropy check on this value and will refuse to start if it does not meet the minimum length requirement.

Security notes:

  • Generate with: openssl rand -hex 32
  • Minimum 32 characters required. Shorter values will cause a startup failure.
  • Changing this value invalidates all active access and refresh tokens, forcing all users to re-authenticate.
  • Never reuse this value across environments (dev/staging/prod).
  • Store in a secrets manager, not in plaintext files.

ENCRYPTION_KEY#

PropertyValue
RequiredYes
Default
Exampleb7e4d219f0c83... (64-character hex string)

256-bit key (32 bytes, encoded as 64 hex characters) used for AES-256-GCM encryption of sensitive data at rest (provider API keys, MCP server auth secrets).

Security notes:

  • Generate with: openssl rand -hex 32
  • Changing this value renders all previously encrypted data (provider API keys, MCP auth secrets) unreadable. You must re-enter those values after rotation.
  • This is the most critical secret in the system. Compromise of this key exposes all stored provider credentials.
  • Store in a hardware security module (HSM) or secrets manager in production.

Server#

SERVER_HOST#

PropertyValue
RequiredNo
Default0.0.0.0
Example127.0.0.1

IP address the servers bind to. Use 0.0.0.0 to listen on all interfaces, or 127.0.0.1 to restrict to localhost only.


GATEWAY_PORT#

PropertyValue
RequiredNo
Default3000
Example8080

TCP port for the gateway server (OpenAI-compatible API and MCP transport).


CONSOLE_PORT#

PropertyValue
RequiredNo
Default3001
Example8081

TCP port for the console server (management API and admin endpoints).


CORS_ORIGINS#

PropertyValue
RequiredNo
Defaulthttp://localhost:5173
Examplehttps://console.example.com,https://admin.example.com

Comma-separated list of allowed CORS origins. Each origin must include the scheme (http:// or https://) and must not include a trailing slash.

Security notes:

  • In production, restrict to only the domain(s) that host your console frontend.
  • Do not use * as this disables CORS protection entirely.

Observability#

CLICKHOUSE_URL#

PropertyValue
RequiredNo
Default
Examplehttp://clickhouse:8123

Base URL of the ClickHouse HTTP interface for audit log storage and search. If not set, audit log ingestion to ClickHouse will be unavailable (entries are still logged to stdout and forwarded to configured log forwarders).


CLICKHOUSE_DB#

PropertyValue
RequiredNo
Defaultthink_watch
Examplethink_watch_prod

Name of the ClickHouse database where audit log tables are stored. ThinkWatch automatically creates the database and tables on startup if they do not exist.


CLICKHOUSE_USER#

PropertyValue
RequiredNo
Defaultdefault
Examplethinkwatch

ClickHouse user for authentication.


CLICKHOUSE_PASSWORD#

PropertyValue
RequiredNo
Default
Exampleyour-clickhouse-password

ClickHouse password for authentication.

Security notes:

  • In production, always set a strong password for ClickHouse.
  • Store in a secrets manager, not in plaintext files.

RUST_LOG#

PropertyValue
RequiredNo
Defaultinfo
Examplethinkwatch=debug,tower_http=debug,sqlx=warn

Controls log verbosity using the tracing-subscriber EnvFilter syntax. Accepts comma-separated directives of the form target=level.

Common configurations:

Use CaseValue
Productioninfo or thinkwatch=info,tower_http=warn
Debugging HTTPthinkwatch=debug,tower_http=debug
Debugging SQLthinkwatch=debug,sqlx=debug
Minimal outputwarn

OIDC / SSO#

All four OIDC variables must be set together to enable SSO. If any are missing, OIDC is disabled and GET /api/auth/sso/authorize returns 500.

OIDC_ISSUER_URL#

PropertyValue
RequiredNo (required if SSO is desired)
Default
Examplehttps://login.microsoftonline.com/tenant-id/v2.0

The OIDC issuer URL. ThinkWatch fetches the .well-known/openid-configuration document from this URL at startup to discover endpoints.


OIDC_CLIENT_ID#

PropertyValue
RequiredNo (required if SSO)
Default
Exampleabcdef12-3456-7890-abcd-ef1234567890

The client ID registered with your OIDC identity provider.


OIDC_CLIENT_SECRET#

PropertyValue
RequiredNo (required if SSO)
Default
Exampleyour-client-secret-value

The client secret for the OIDC application.

Security notes:

  • This is a sensitive credential. Store it in a secrets manager.
  • Rotate periodically according to your IdP’s recommendations.

OIDC_REDIRECT_URL#

PropertyValue
RequiredNo (required if SSO)
Default
Examplehttps://console.example.com/api/auth/sso/callback

The full URL that the OIDC provider redirects to after authentication. This must exactly match the redirect URI registered in your IdP configuration and must be reachable by the user’s browser.


Provider Configuration#

Providers are configured through the admin Web UI (Admin > Providers) or the POST /api/admin/providers API. Each provider type has specific configuration requirements:

OpenAI#

FieldValue
provider_typeopenai
base_urlhttps://api.openai.com
api_keysk-... (OpenAI API key)

Models with prefixes gpt-, o1-, o3-, o4- are automatically routed to this provider.

Anthropic#

FieldValue
provider_typeanthropic
base_urlhttps://api.anthropic.com
api_keysk-ant-... (Anthropic API key)

Models with prefix claude- are automatically routed to this provider.

Google Gemini#

FieldValue
provider_typegoogle
base_urlhttps://generativelanguage.googleapis.com
api_keyGoogle AI API key

Models with prefix gemini- are automatically routed to this provider.

Azure OpenAI#

FieldValue
provider_typeazure
base_urlhttps://{resource}.openai.azure.com
api_keyAzure API key
config_json{"api_version": "2024-12-01-preview"}

Azure OpenAI uses the api-key header (not Bearer token) for authentication. The api_version is passed as a query parameter. Azure does not support automatic model routing — you must explicitly register models via Admin > Models.

AWS Bedrock#

FieldValue
provider_typebedrock
base_urlAWS region (e.g. us-east-1)
api_keyACCESS_KEY_ID:SECRET_ACCESS_KEY

AWS Bedrock uses SigV4 request signing via the official aws-sigv4 Rust crate. The base_url field specifies the AWS region, and the api_key field contains the IAM credentials in ACCESS_KEY_ID:SECRET_ACCESS_KEY format. Streaming uses the native Bedrock binary event-stream protocol (Converse API). Like Azure, Bedrock does not support automatic model routing — you must explicitly register models via Admin > Models.

Custom (OpenAI-compatible)#

FieldValue
provider_typecustom
base_urlAny OpenAI-compatible endpoint URL
api_keyBearer token for the endpoint

Use this type for self-hosted models (vLLM, Ollama, LiteLLM, etc.) or any third-party service that implements the OpenAI API format.

Provider Auto-Loading#

On startup, ThinkWatch loads all active providers from the database and registers them in the model router. Models are routed based on:

  1. Prefix matching (for OpenAI, Anthropic, Google): Models matching the provider’s default prefix are automatically routed.
  2. Explicit registration (for Azure, Bedrock, Custom): Models must be registered via the Admin > Models page with a specific provider assignment.

Configuration Patterns#

Development vs Production#

SettingDevelopmentProduction
DATABASE_URLLocal PostgreSQL without SSLManaged PostgreSQL with sslmode=require
REDIS_URLLocal Redis without authRedis with requirepass or managed Redis
JWT_SECRETAny stable value for dev convenienceCryptographically random 256-bit key
ENCRYPTION_KEYAny stable 32-byte hex for dev convenienceCryptographically random, stored in HSM
CORS_ORIGINShttp://localhost:5173https://console.yourdomain.com
RUST_LOGthinkwatch=debug,tower_http=debuginfo or thinkwatch=info
OIDC variables(unset unless testing SSO)Fully configured

Using .env Files#

For local development, create a .env file in the project root:

# .env (DO NOT commit this file)
DATABASE_URL=postgres://thinkwatch:devpass@localhost:5432/thinkwatch
REDIS_URL=redis://localhost:6379
JWT_SECRET=dev-only-jwt-secret-do-not-use-in-production-000000
ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
CORS_ORIGINS=http://localhost:5173
RUST_LOG=thinkwatch=debug,tower_http=debug

ThinkWatch loads .env automatically via the dotenvy crate. The .env file should be listed in .gitignore.

Environment File#

ThinkWatch uses a single .env file at the project root for all environments:

  • Development: cargo run loads via dotenvy, docker compose loads via --env-file .env (configured in Makefile)
  • Production: Uses .env.production at the project root, loaded via make deploy

There is no separate deploy/.env file. Copy .env.example to get started:

cp .env.example .env
# Edit .env with your values, or run:
# deploy/generate-secrets.sh

Docker / Docker Compose#

Pass environment variables through docker-compose.yml:

services:
  thinkwatch:
    image: thinkwatch:latest
    environment:
      DATABASE_URL: postgres://thinkwatch:${DB_PASSWORD}@postgres:5432/thinkwatch
      REDIS_URL: redis://redis:6379
      JWT_SECRET: ${JWT_SECRET}
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}
      CORS_ORIGINS: https://console.example.com
      CLICKHOUSE_URL: http://clickhouse:8123
      RUST_LOG: info
    ports:
      - "3000:3000"
      - "3001:3001"

Use a .env file or shell exports to provide ${DB_PASSWORD}, ${JWT_SECRET}, and ${ENCRYPTION_KEY} without hardcoding them in the compose file.

Kubernetes Secrets#

Create a Kubernetes Secret for sensitive values:

kubectl create secret generic thinkwatch-secrets \
  --from-literal=JWT_SECRET="$(openssl rand -hex 32)" \
  --from-literal=ENCRYPTION_KEY="$(openssl rand -hex 32)" \
  --from-literal=DATABASE_URL="postgres://user:pass@pg-host:5432/thinkwatch?sslmode=require" \
  --from-literal=REDIS_URL="rediss://:password@redis-host:6380" \
  --from-literal=OIDC_CLIENT_SECRET="your-oidc-secret"

Reference the secret in your Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: thinkwatch
spec:
  template:
    spec:
      containers:
        - name: thinkwatch
          image: thinkwatch:latest
          envFrom:
            - secretRef:
                name: thinkwatch-secrets
          env:
            - name: CORS_ORIGINS
              value: "https://console.example.com"
            - name: GATEWAY_PORT
              value: "3000"
            - name: CONSOLE_PORT
              value: "3001"
            - name: CLICKHOUSE_URL
              value: "http://clickhouse:8123"
            - name: RUST_LOG
              value: "info"

Generating Secure Random Keys#

Use openssl to generate cryptographically secure random values:

# Generate a 256-bit key (for JWT_SECRET or ENCRYPTION_KEY)
openssl rand -hex 32

# Generate a 128-bit key (for less critical uses)
openssl rand -hex 16

# Generate a base64-encoded key (alternative format)
openssl rand -base64 32

Both JWT_SECRET and ENCRYPTION_KEY expect a 64-character hex string (representing 32 bytes / 256 bits).


Dynamic Configuration (Web UI)#

Many settings that previously required environment variables are now stored in the database and configurable through the admin Web UI at runtime. These settings can also be managed via the GET/PATCH /api/admin/settings API endpoints.

Changes to dynamic settings take effect immediately without requiring a server restart.

Authentication & JWT#

SettingDefaultDescription
jwt_access_ttl_seconds900Access token lifetime in seconds (15 minutes)
jwt_refresh_ttl_seconds604800Refresh token lifetime in seconds (7 days)

Cache#

SettingDefaultDescription
cache_ttl_seconds300Default cache TTL for various caches

Security#

SettingDefaultDescription
signature_drift_seconds300Maximum allowed clock drift for signed requests
nonce_ttl_seconds300TTL for nonce values used in replay protection
content_filter_patterns[]Content filter patterns (max 500; severity enum: low, medium, high, critical)
pii_patterns[]PII detection regex patterns (max 100; max 1000 chars each; validated at save time)

Budget#

SettingDefaultDescription
budget_warning_threshold0.8Budget utilization ratio that triggers a warning
budget_critical_threshold0.95Budget utilization ratio that triggers a critical alert

API Key Policies#

SettingDefaultDescription
api_key_max_expiry_days365Maximum allowed expiry for new API keys
api_key_default_rate_limit_rpm60Default RPM limit for new API keys

General#

SettingDefaultDescription
data_retention_days30Days to retain soft-deleted records before purge
site_nameThinkWatchSite name displayed in the Web UI

Startup Validation#

ThinkWatch validates all configuration and dependencies at startup and will refuse to start if:

  • DATABASE_URL is missing or the database is unreachable
  • REDIS_URL is missing or Redis is unreachable
  • JWT_SECRET is missing or shorter than 32 characters
  • JWT_SECRET fails the entropy check (e.g., all identical characters)
  • ENCRYPTION_KEY is missing or not a valid 64-character hex string
  • OIDC_* variables are partially configured (all four must be set, or none)

Additionally, the server performs dependency health checks at startup:

  • PostgreSQL: Verifies the connection and runs a test query
  • Redis: Verifies the connection with a PING command
  • ClickHouse: If configured, verifies the connection and tables exist (non-blocking — logs a warning if unavailable)

Check the application logs if the server fails to start. Missing or invalid configuration will be reported with clear error messages.