DEEIX Chat separates static startup configuration from runtime business settings. This page shows where each setting lives, how priority works, and what to change before production.
Configuration model#
DEEIX Chat reads three kinds of configuration. Keep them separate so deployment, migration, and secret rotation stay predictable.
| Layer | What it covers | Where it lives | How to change it |
|---|---|---|---|
| Startup configuration | App, branding, HTTP service, security, database, cache, storage, GeoIP, tracing | config.yaml and environment variables | Edit and restart |
| Runtime business settings | Login, conversation, models, files, RAG, MCP, billing, announcements | Database system_settings | Admin console |
| Frontend build configuration | Browser API origin | NEXT_PUBLIC_API_BASE_URL at build time | Rebuild the frontend |
Priority is always environment variables > config.yaml > built-in defaults.
Config file resolution#
The backend looks for the config file in the working directory:
- Started from the repository root:
./config.yaml - Started from
backend/:../config.yaml - Docker:
/app/config.yaml, mounted fromdeploy/config.yaml - Custom path: set
CONFIG_FILEto a path the process or container can read
config.yaml#
config.yaml holds only what the service needs before it starts. Models, routes, pricing, subscriptions, RAG, MCP, and file policy are runtime business settings, not static YAML.
App and branding#
config.yaml
| Field | Purpose |
|---|---|
app.name | Application name used in logs and tracing. |
app.env | dev/development or prod/production. Defaults to prod when omitted. dev enables Swagger and relaxes production checks. |
branding.* | Frontend title, short name, description, logo, favicon, PWA icons, and Apple touch icon. Changes take effect after a restart; no frontend rebuild is needed. |
HTTP service#
config.yaml
| Field | Purpose | Production requirement |
|---|---|---|
server.http_port | API listen port. | Update the compose port mapping if you change it. |
server.cors_allow_origin | Frontend origins allowed to call the API. | Exact origins; * is rejected. |
server.trusted_proxies | CIDRs allowed to set forwarded headers. | Only real proxy sources. |
server.public_api_base_url | Public API URL for links and callbacks. | HTTPS. |
server.public_web_base_url | Public web URL for links and redirects. | HTTPS. |
server.frontend_dist_dir | Directory the Go service serves static frontend files from. | /app/frontend/out in the Docker image. |
server.shutdown_timeout_seconds | Drain window for in-flight requests. | Keep below the orchestrator termination grace period. |
Security#
config.yaml
| Secret | Minimum | Purpose |
|---|---|---|
security.jwt_secret / JWT_SECRET | 16 characters | Signs login sessions and access tokens. |
security.data_encryption_key / DATA_ENCRYPTION_KEY | 32 characters | Derives the AES-GCM key for upstream API keys, SSO secrets, MCP tokens, sensitive settings, and TOTP secrets. Keep it stable after release. |
security.mcp_user_context_secret | - | Signs ${DEEIX_SIGNED_USER_CONTEXT} values. Required only when an MCP server uses them. |
security.ssrf_protection_enabled | - | Blocks outbound requests to private and metadata networks. Defaults to false. |
security.ssrf_allowed_hosts | - | Exact hostnames trusted for deployment-level integrations. |
security.ssrf_allowed_cidrs | - | CIDR ranges trusted for deployment-level integrations. |
security.turnstile_siteverify_url | - | Cloudflare Turnstile verification endpoint. Override only for a compatible proxy. |
Security secret generator
security.jwt_secret
JWT_SECRETsecurity.data_encryption_key
DATA_ENCRYPTION_KEYGenerated locally in your browser. Keys are not collected, stored, or sent anywhere.
Production mode rejects an empty JWT_SECRET, the built-in development default, a secret shorter than 16 characters, and a DATA_ENCRYPTION_KEY shorter than 32 characters. Changing data_encryption_key makes existing ciphertext unreadable, so plan a re-encryption before you rotate it.
Database, cache, and storage#
config.yaml
| Setting | Options | Notes |
|---|---|---|
database.driver | postgres, sqlite | PostgreSQL for multi-node and high-concurrency deployments. SQLite is single-node only. |
database.postgres.dsn | - | PostgreSQL connection string. |
database.sqlite.path | - | SQLite file path. The Docker lightweight profile uses /app/data/deeix.db. |
cache.driver | redis, memory | memory works only in a single process. |
database.redis.* | - | Redis address, username, password, DB, and TLS. |
storage.backend | local, s3 | Use S3-compatible storage for multi-instance deployments. |
storage.local.root_dir | - | Local file directory. The Docker profile uses /app/storage. |
storage.s3.* | - | Endpoint, region, bucket, prefix, credentials, and path-style access. region and bucket are required when backend is s3. |
GeoIP and tracing#
config.yaml
| Setting | Options | Notes |
|---|---|---|
geoip.provider | none, ipwhois, ipinfo, mmdb | mmdb uses a local GeoLite2 database. |
geoip.base_url, geoip.token | - | GeoIP HTTP service URL and token. The default URL is https://ipwho.is. |
geoip.database_url, geoip.database_path, geoip.database_max_bytes, geoip.refresh_interval_hours | - | MMDB download URL, local path, maximum download size, and refresh interval. |
observability.tracing.endpoint | - | Setting an OTLP endpoint enables tracing automatically. |
observability.tracing.protocol | grpc, http | Defaults to grpc. |
observability.tracing.sampling_rate | 0 to 1 | Set a sampling rate before you enable tracing. |
Environment variables#
Environment variables override matching config.yaml values. Use them for container platforms, CI/CD, and secret managers.
| Area | Variables | Config fields |
|---|---|---|
| Frontend build | NEXT_PUBLIC_API_BASE_URL | Browser API base URL, set at build time |
| Config file | CONFIG_FILE | Config file path |
| Application | APP_NAME, APP_ENV | app.* |
| HTTP service | HTTP_PORT, CORS_ALLOW_ORIGIN, TRUSTED_PROXIES, PUBLIC_API_BASE_URL, PUBLIC_WEB_BASE_URL, FRONTEND_DIST_DIR | server.* |
| HTTP timeouts | HTTP_READ_HEADER_TIMEOUT_SECONDS, HTTP_READ_TIMEOUT_SECONDS, HTTP_IDLE_TIMEOUT_SECONDS, HTTP_MAX_HEADER_BYTES, HTTP_SHUTDOWN_TIMEOUT_SECONDS | server.* |
| Security | JWT_SECRET, MCP_USER_CONTEXT_SECRET, DATA_ENCRYPTION_KEY, SSRF_PROTECTION_ENABLED, SSRF_ALLOWED_HOSTS, SSRF_ALLOWED_CIDRS, TURNSTILE_SITEVERIFY_URL | security.* |
| Database | DATABASE_DRIVER | database.driver |
| PostgreSQL | POSTGRES_DSN, POSTGRES_MAX_OPEN_CONNS, POSTGRES_MAX_IDLE_CONNS, POSTGRES_CONN_MAX_LIFETIME_MINUTES, POSTGRES_CONN_MAX_IDLE_TIME_MINUTES | database.postgres.* |
| SQLite | SQLITE_PATH, SQLITE_DSN, SQLITE_MAX_OPEN_CONNS, SQLITE_BUSY_TIMEOUT_MS, SQLITE_CACHE_SIZE_KB, SQLITE_MMAP_SIZE_BYTES, SQLITE_SYNCHRONOUS, SQLITE_TEMP_STORE | database.sqlite.* |
| Cache | CACHE_DRIVER | cache.driver |
| Redis | REDIS_ADDR, REDIS_USERNAME, REDIS_PASSWORD, REDIS_DB, REDIS_TLS_ENABLED, REDIS_TLS_INSECURE_SKIP_VERIFY | database.redis.* |
| Storage | STORAGE_BACKEND, STORAGE_ROOT_DIR | storage.backend, storage.local.root_dir |
| S3 storage | STORAGE_S3_ENDPOINT, STORAGE_S3_REGION, STORAGE_S3_BUCKET, STORAGE_S3_PREFIX, STORAGE_S3_ACCESS_KEY_ID, STORAGE_S3_SECRET_ACCESS_KEY, STORAGE_S3_FORCE_PATH_STYLE | storage.s3.* |
| GeoIP | GEOIP_PROVIDER, GEOIP_BASE_URL, GEOIP_TOKEN, GEOIP_TIMEOUT_MS, GEOIP_DATABASE_URL, GEOIP_DATABASE_PATH, GEOIP_DATABASE_MAX_BYTES, GEOIP_REFRESH_INTERVAL_HOURS | geoip.* |
| OpenTelemetry | OTEL_ENABLED, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_INSECURE, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_TRACES_SAMPLER_ARG, OTEL_SAMPLING_RATE | observability.tracing.* |
APP_ENV accepts dev/development and prod/production and normalizes to dev or prod. When omitted it defaults to prod. OTEL_TRACES_SAMPLER_ARG takes priority over OTEL_SAMPLING_RATE.
Runtime business settings in the admin console#
Authentication, registration, conversation behavior, model option policy, file processing, RAG, embeddings, MCP, billing, payments, and announcements are stored in system_settings. Change them from the admin console, not from config.yaml.
| Admin section | What it controls | Guide |
|---|---|---|
| Statistics | Usage by user, permission group, and model. | Statistics |
| Accounts | Users, roles, status, subscriptions, balances, and security. | Accounts |
| Permission Groups | Rate multiplier, member users, and accessible models. | Permission groups |
| Upstreams | Provider channels, base URLs, API keys, protocols, timeouts, and circuit breaking. | Upstreams |
| Models | Platform models, sources, routing, capabilities, and native tools. | Models |
| Tools | MCP servers, tool sync, tool enablement, ordering, and execution limits. | Tools |
| Billing | Billing mode, model pricing, tool pricing, plans, payments, redemption codes, and usage logs. | Billing |
| Announcements | Post-sign-in notices with type, pin state, and Markdown content. | Announcements |
| Logs | Audit, usage, authentication, and system events. | Logs |
| Content moderation | Moderation service and input/output policies. Superadmin only. | Content moderation |
| Login & auth | Login page, registration, email verification, providers, Turnstile, token lifetime, and rate limits. | Sign-in & auth |
| Conversation | Default model, task model, system prompt, interactive components, context management, and option passthrough. | Conversation |
| Files & retrieval | Upload limits, extraction, OCR, full-context injection, embeddings, and RAG. | Files & retrieval |
| Knowledge bases | The knowledge base switch and built-in knowledge bases. | - |
| About | Version, update check, official links, and license. | About |
Docker Compose#
All compose files are built around the app service. It binds to 127.0.0.1:8080 by default, mounts ./config.yaml read-only to /app/config.yaml, and persists two volumes.
| Data | Container path |
|---|---|
| SQLite database | /app/data/deeix.db |
| Uploaded and generated files | /app/storage |
| PostgreSQL data | /var/lib/postgresql/data, full profile only |
| Redis data | /data, full profile only |
docker-compose.full.yml injects connection values for the bundled services:
docker-compose.full.yml
Replace the PostgreSQL and Redis passwords before production use. To run a local image, build it from the repository root and set DEEIX_CHAT_IMAGE.
OAuth callbacks for web, app, and desktop#
Set PUBLIC_API_BASE_URL to the externally reachable API origin before you enable third-party sign-in. For each OIDC/OAuth2 provider, register:
text
Web, app, and desktop clients reuse this instance callback. Desktop clients use a loopback redirect (RFC 8252) and need no custom URL scheme. See Desktop App.
Production checklist#
app.envisprodorproduction.jwt_secretanddata_encryption_keyare strong random values stored in a secret manager.public_api_base_urlandpublic_web_base_urluse HTTPS.cors_allow_originlists exact origins and no wildcard.trusted_proxiescontains only real reverse proxy CIDRs.- The database is PostgreSQL and the cache is Redis.
/app/dataand/app/storageare on persistent volumes with backups.- Multi-instance deployments use S3-compatible storage.
- The bundled PostgreSQL and Redis passwords are replaced.
- Tracing is enabled only with a collector and a sampling rate.