# ODS Configuration # Copy this file to .env and edit values before starting: # cp .env.example .env # # The installer (install-core.sh) generates .env automatically with # secure random secrets. This file documents all available variables. # ODS version (auto-set by installer, used by ods-cli for compat checks) # ODS_VERSION=3.0.0 # LiteLLM proxy API key for internal service auth # TARGET_API_KEY=not-needed # ═══════════════════════════════════════════════════════════════════ # REQUIRED — these must be set or docker compose will refuse to start # ═══════════════════════════════════════════════════════════════════ # Session signing for Open WebUI (generate: openssl rand -hex 32) WEBUI_SECRET=CHANGEME # n8n workflow automation credentials N8N_USER=admin@ods.local N8N_PASS=CHANGEME # LiteLLM API gateway key (generate: echo "sk-ods-$(openssl rand -hex 16)") LITELLM_KEY=CHANGEME # LiveKit real-time communication credentials LIVEKIT_API_KEY=CHANGEME LIVEKIT_API_SECRET=CHANGEME # Dify agent platform secret key DIFY_SECRET_KEY=CHANGEME # SearXNG session secret (generate: openssl rand -hex 32) SEARXNG_SECRET=CHANGEME # OpenCode web UI password (generate: openssl rand -base64 16) OPENCODE_SERVER_PASSWORD=CHANGEME # ═══════════════════════════════════════════════════════════════════ # Network Binding # ═══════════════════════════════════════════════════════════════════ # Bind address for all Docker port bindings. # 127.0.0.1 = localhost only (secure default) # 0.0.0.0 = accessible from LAN (headless servers, see SECURITY.md) # BIND_ADDRESS=127.0.0.1 # ═══════════════════════════════════════════════════════════════════ # LLM Backend Mode # ═══════════════════════════════════════════════════════════════════ # local = llama-server (default, requires GPU or CPU inference) # cloud = LiteLLM -> cloud APIs (no local GPU needed) # hybrid = local primary, cloud fallback ODS_MODE=local # Linux API-only choice: ./install.sh --gateway-only --external-llm-url URL # --external-llm-provider openai-compatible --external-llm-model MODEL. # This keeps LiteLLM and Dashboard but leaves out managed llama-server and # Open WebUI. Add --with-webui to include the chat UI. The installer maintains # these values on reruns; edit through installer flags rather than .env alone. ODS_GATEWAY_ONLY=false ENABLE_OPEN_WEBUI=true ENABLE_DEVTOOLS=false # Model Switchboard mode: enabled (default) / observe / legacy. # enabled routes supported apps through the stable ods/current alias and # provides request-safe model swaps. observe and legacy are rollback modes. ODS_MODEL_SWITCHBOARD=enabled # Model profiles: observe (default) / enabled / off. # The first time a model runs on this machine, ODS measures what it can do # (answers, tool calls, thinking, images, speed) and shows it on the Models # page. observe only shows it, enabled also lets apps use it, off skips it. ODS_MODEL_PROFILES=observe # Inference backend engine: llama-server (NVIDIA, AMD, CPU, Intel), # litellm (cloud), or external (installer-validated Ollama/LM Studio or any # OpenAI-compatible server you run, Lemonade included) LLM_BACKEND=llama-server # API base path of the inference backend (set by installer) LLM_API_BASE_PATH=/v1 LLM_API_URL=http://llama-server:8080 # Enabled switchboard installs set these so Open WebUI talks to LiteLLM/ods-current. OPEN_WEBUI_LLM_BASE_URL= OPEN_WEBUI_LLM_API_KEY= # Exact ordinary-model ID used by Open WebUI task routing. The installer sets # stable gateway/external IDs where needed. Direct llama.cpp installs leave it # empty so the active GGUF filename is followed automatically. OPEN_WEBUI_TASK_MODEL= # LLM_URL= # Optional dashboard-api diagnostics override; normally follows LLM_API_URL # Reuse a host-managed Ollama or LM Studio model instead of downloading and # starting ODS's llama-server. Configure this through install.sh so the # endpoint/model are validated and the Compose topology is updated atomically: # ./install.sh --external-llm-url http://127.0.0.1:11434 \ # --external-llm-provider ollama --external-llm-model qwen3.5:9b # Interactive installs can discover a matching model and ask before reuse. # Non-interactive discovery is opt-in with --reuse-external-llm. # Use ./install.sh --no-external-llm to return a persisted install to managed # local inference. EXTERNAL_LLM_URL is host-facing; the installer derives the # container-facing host.docker.internal URL. # Authenticated OpenAI-compatible endpoints can add --external-llm-key-file # /path/to/private.key (owner-owned, mode 0600/0400). The installer stores a # private copy at config/litellm/external-upstream.key; the key is not written # to .env or the rendered LiteLLM YAML. A different endpoint does not inherit # that key; pass the new endpoint's key file explicitly. # Re-run with --no-external-llm-key to stop sending a saved key. EXTERNAL_LLM_URL= EXTERNAL_LLM_CONTAINER_URL= EXTERNAL_LLM_PROVIDER= EXTERNAL_LLM_MODEL= SKIP_MODEL_DOWNLOAD=false # Remote GPU provider metadata. Remote routing is active only when # ODS_MODE=cloud and REMOTE_LLM_ENABLED=true. Provider API keys, peer tokens, # SSH identities, and CA material are write-only lifecycle inputs; do not put # them in .env. REMOTE_LLM_ENABLED=false REMOTE_LLM_TRANSPORT= REMOTE_LLM_BASE_URL= REMOTE_LLM_MODEL= REMOTE_LLM_TLS_CA_FILE= REMOTE_LLM_SSH_HOST= REMOTE_LLM_SSH_USER= REMOTE_LLM_SSH_PORT= REMOTE_LLM_SSH_INFERENCE_HOST= REMOTE_LLM_SSH_INFERENCE_PORT= REMOTE_LLM_SSH_CONTROL_HOST= REMOTE_LLM_SSH_CONTROL_PORT= REMOTE_ODS_PEER_URL= # Numeric host data-directory GID added only to the hardened remote-provider # containers so they can read lifecycle secrets written mode 0640. REMOTE_PROVIDER_DATA_GID=1000 # ODS Talk image attachment vision backend. Leave empty to use the local # inference backend. May be a host root (http://host:8080) or an # OpenAI-compatible base URL (http://host:8080/v1 or /api/v1). ODS_TALK_VISION_URL= ODS_TALK_VISION_KEY= # Empty uses the active model. ODS_TALK_VISION_MODEL= # AMD llama.cpp runtime selected by the installer. # Linux AMD: llama-server / vulkan (default) or rocm / container / linux-container # Windows Portal AMD: llama-server / vulkan / host / windows-portal-llama-server AMD_INFERENCE_RUNTIME= AMD_INFERENCE_BACKEND= AMD_INFERENCE_LOCATION= AMD_INFERENCE_PORT=8080 AMD_INFERENCE_SUPPORTED_BACKENDS= AMD_INFERENCE_RUNTIME_MODE= AMD_INFERENCE_MANAGED= # Host-native llama-server (the Windows Portal runs llama-server.exe while this # stack runs in WSL). Windows setup sets these; leave them empty otherwise. NATIVE_LLM_BASE_URL= NATIVE_LLM_CONTAINER_BASE_URL= ODS_HOST_LLM_TRANSPORT=direct # LLAMA_SERVER_API_KEY= # Generated by Windows setup; never on a command line # ═══════════════════════════════════════════════════════════════════ # Provider and Hub Credentials # ═══════════════════════════════════════════════════════════════════ ANTHROPIC_API_KEY= OPENAI_API_KEY= # Optional in every mode: read token for private/gated Hugging Face models. HF_TOKEN= # Comma-separated HTTPS hosts permitted for model artifact downloads. # ODS_MODEL_DOWNLOAD_ALLOWED_HOSTS=huggingface.co,www.huggingface.co,hf.co TOGETHER_API_KEY= MINIMAX_API_KEY= # ═══════════════════════════════════════════════════════════════════ # LLM Settings (llama-server) # ═══════════════════════════════════════════════════════════════════ # Optional model family profile for installer-driven tier selection. # qwen = keep the current stable ODS defaults # gemma4 = always use Gemma 4 tier mappings when possible # auto = prefer Gemma 4 on capable hardware, keep Qwen fallback for minimum/cloud paths MODEL_PROFILE=qwen # Model GGUF filename override (installer normally rewrites this from tier + MODEL_PROFILE) GGUF_FILE=Qwen3.5-9B-Q4_K_M.gguf # Context window size (tokens) CTX_SIZE=16384 # GPU backend set by the installer: nvidia, amd, apple, cpu, jetson, or sycl (Intel Arc) GPU_BACKEND=nvidia # Unified system RAM in GB (macOS Apple Silicon only — written by env-generator.sh). # Passed to llama.cpp for the Metal backend to size the unified-memory pool. # HOST_RAM_GB=24 # Model name override (installer normally rewrites this from tier + MODEL_PROFILE) LLM_MODEL=qwen3.5-9b # Installer recommendation metadata. During fast-start bootstrap, LLM_MODEL/GGUF_FILE # may temporarily point at the small bootstrap model while these fields keep the # full hardware-selected target visible in the dashboard. MODEL_RECOMMENDED_MODEL=qwen3.5-9b MODEL_RECOMMENDED_GGUF=Qwen3.5-9B-Q4_K_M.gguf MODEL_RECOMMENDED_CONTEXT=65536 MODEL_RECOMMENDATION_SOURCE=catalog_fit_pre_download MODEL_RECOMMENDATION_POLICY=context-aware-curated-fit-v2 MODEL_RECOMMENDATION_CONFIDENCE=high MODEL_RECOMMENDATION_REASON=Curated fit (context-aware-curated-fit-v2): Qwen 3.5 9B is the highest-priority installable model for discrete memory that fits 12.0 GiB GPU VRAM on nvidia (leaving at least 0.36 GiB free) at 64K context; it needs about 7.77 GiB (weights 5.29 + KV 2.00 + recurrent state 0.05 + overhead 0.43). Throughput requires a local benchmark after first launch. MODEL_RECOMMENDED_ALTERNATIVES=qwen3.5-9b-q4:65536:7.77;qwen3.5-4b-q4:65536:4.99;nvidia-nemotron3-nano-4b-q4:65536:4.11 MODEL_PERFORMANCE_SOURCE=benchmark_required MODEL_PERFORMANCE_LABEL=Benchmark after first launch MODEL_RUNTIME_PROFILE= MODEL_RUNTIME_PROFILE_LABEL= MODEL_RUNTIME_PROFILE_SOURCE= SYSTEM_RAM_GB=32 # Optional llama.cpp image override (installer sets this automatically for runtime profiles) # LLAMA_SERVER_IMAGE=ghcr.io/ggml-org/llama.cpp:server-cuda-b11429@sha256:883915ea20a4b350e98f7284098f4d400c21e9b366e248d397cd42d90602a84c # Optional explicit fallback if a custom llama.cpp image tag disappears # LLAMA_SERVER_IMAGE_FALLBACK=ghcr.io/ggml-org/llama.cpp:server-cuda-b9014@sha256:fcf285820892e7ce3218379634e3590826fc697e8b6745b9392072462e355c4f # The AMD overlays do not read LLAMA_SERVER_IMAGE; their images are pinned in # config/backends/amd.json. AMD_INFERENCE_BACKEND=rocm selects the ROCm image. # ─── Architecture-specific overrides ──────────────────────────────────────────── # WHISPER_ACCELERATION is normally written by the installer. On NVIDIA systems # with drivers too old for the CUDA Whisper image, ODS keeps the rest of the GPU # stack enabled and runs Whisper on CPU. # WHISPER_ACCELERATION=cuda # WHISPER_IMAGE is a forward-compat escape hatch. The fallback may set the # CPU image when the CUDA tag cannot run on the installed driver. # WHISPER_IMAGE=ghcr.io/speaches-ai/speaches:0.9.0-rc.3-cuda # llama-server inference tuning (advanced) # N_GPU_LAYERS=auto # auto | all | non-negative layer count # LLAMA_BATCH_SIZE=2048 # Batch size for prompt processing (higher = faster prefill) # LLAMA_THREADS=4 # CPU threads for non-GPU work # LLAMA_PARALLEL=1 # Concurrent request slots (increase for multi-user) # LLAMA_ARG_FLASH_ATTN=auto # auto | on | off. Use on for long-context CUDA/Metal/SYCL tuning. # LLAMA_ARG_CACHE_TYPE_K=f16 # KV cache key type: f16 (default) or q8_0 for lower VRAM/RAM. # LLAMA_ARG_CACHE_TYPE_V=f16 # KV cache value type: f16 (default) or q8_0 for lower VRAM/RAM. # LLAMA_ARG_N_CPU_MOE=25 # Optional MoE only: keep first N MoE expert layers on CPU/RAM. # LLAMA_ARG_NO_CACHE_PROMPT=1 # Optional profile flag for long-context MoE runs. Any value, even 0, disables prompt caching in Docker. # LLAMA_ARG_CHECKPOINT_EVERY_NT=-1 # Optional profile flag to disable context checkpoints (llama.cpp default 8192). # LLAMA_ARG_CTX_CHECKPOINTS=32 # Native macOS default when unset; prompt checkpoints per slot. Lower (or 0) saves memory. # LLAMA_SPEC_TYPE=none # NVIDIA/CPU Docker and native macOS default is ngram-mod (lossless n-gram speculation); none turns it off. # LLAMA_ARG_SPEC_TYPE=draft-mtp # Optional per-model override: only for MTP-capable GGUFs and llama.cpp builds. # LLAMA_ARG_SPEC_DRAFT_N_MAX=3 # Optional: speculative draft cap; benchmark per model/runtime. # LLAMA_ARG_SPEC_DRAFT_TYPE_K=q4_0 # Optional, native macOS/Windows only: qualified draft key cache type. # LLAMA_ARG_SPEC_DRAFT_TYPE_V=q4_0 # Optional, native macOS/Windows only: qualified draft value cache type. # LLAMA_ARG_SPEC_DRAFT_CACHE_TYPE_K=q4_0 # Optional, Docker: draft key cache type (the name llama.cpp reads). # LLAMA_ARG_SPEC_DRAFT_CACHE_TYPE_V=q4_0 # Optional, Docker: draft value cache type (the name llama.cpp reads). # LLAMA_ARG_CHECKPOINT_MIN_SPACING_NT=1024 # Optional: llama.cpp b9310+ checkpoint spacing; the NVIDIA default supports it; b9014 backends ignore it. # ODS_ACTIVE_MODEL_STORE=default # Registered store ID; default uses data/models. # LLAMA_CPU_LIMIT=12.0 # Auto-generated: capped to CPUs actually exposed by Docker # LLAMA_CPU_RESERVATION=2.0 # Auto-generated: reservation capped to the same ceiling # TTS_CPU_LIMIT=8.0 # Auto-generated: capped to Docker CPUs # TTS_WORKERS=1 # Default: one Kokoro model copy; raise only for higher concurrency # TTS_THREADS=4 # Auto: per-worker CPU threads, at most 4 and within TTS_CPU_LIMIT # TTS_CPU_RESERVATION=2.0 # Auto-generated: capped to the TTS limit # WHISPER_CPU_LIMIT=4.0 # Auto-generated: capped to Docker CPUs # WHISPER_CPU_RESERVATION=1.0 # Auto-generated: capped to the Whisper limit # HERMES_CPU_LIMIT=4.0 # Auto-generated: capped to Docker CPUs # HERMES_CPU_RESERVATION=0.5 # Auto-generated: capped to the Hermes limit # COMFYUI_CPU_LIMIT=16.0 # Auto-generated: capped to Docker CPUs # COMFYUI_CPU_RESERVATION=2.0 # Auto-generated: capped to the ComfyUI limit # LLAMA_START_PERIOD=240s # Healthcheck grace window for cold model load (bump for 70B-class on slow NVMe) # ═══════════════════════════════════════════════════════════════════ # Ports — all overridable, defaults shown # ═══════════════════════════════════════════════════════════════════ # llama-server API (external → internal 8080) OLLAMA_PORT=11434 # Open WebUI (external → internal 8080) WEBUI_PORT=3000 # SEARXNG_PORT=8888 # SearXNG metasearch (external → internal 8080) # PERPLEXICA_PORT=3004 # Perplexica deep research (external → internal 3000) # WHISPER_PORT=9000 # Whisper STT (external → internal 8000) # TTS_PORT=8880 # Kokoro TTS (external → internal 8880) # N8N_PORT=5678 # n8n workflows (external → internal 5678) # QDRANT_PORT=6333 # Qdrant vector DB (external → internal 6333) # QDRANT_GRPC_PORT=6334 # Qdrant gRPC (external → internal 6334) # EMBEDDINGS_PORT=8090 # Text embeddings (external → internal 80) # LITELLM_PORT=4000 # LiteLLM gateway (external → internal 4000) # SHIELD_PORT=8085 # Privacy Shield (external → internal 8085) # DASHBOARD_API_PORT=3002 # Dashboard API (external → internal 3002) # DASHBOARD_PORT=3001 # Dashboard on this machine, no sign-in (host loopback → internal 3001) # DASHBOARD_REMOTE_PORT=3011 # Dashboard from another machine, sign-in required (BIND_ADDRESS → internal 3011) # COMFYUI_PORT=8188 # ComfyUI image gen (external → internal 8188) # TOKEN_SPY_PORT=3005 # Token Spy usage monitor (external → internal 8080) # OPENCODE_PORT=3003 # OpenCode IDE web UI (host service) # ═══════════════════════════════════════════════════════════════════ # Optional Security # ═══════════════════════════════════════════════════════════════════ # Host Agent bind address (leave empty for platform-aware default). # macOS/Windows: defaults to 127.0.0.1 (Docker Desktop routes via loopback). # Linux: auto-detects Docker bridge gateway IP (e.g. 172.17.0.1) so containers # can reach the agent while LAN devices cannot. Falls back to 127.0.0.1 if # detection fails. Set explicitly to override. # ODS_AGENT_BIND= # Host Agent HTTP port used by dashboard-api for privileged host operations. # ODS_AGENT_PORT=7710 # Hostname/IP dashboard-api containers use to reach ods-host-agent. # Docker Desktop uses host.docker.internal; Colima installers set the private # vmnet host gateway because its user-mode host route can become unreachable. # ODS_AGENT_HOST=host.docker.internal # Managed macOS/Colima private bridge state. Installers discover these values; # do not set them manually unless repairing a custom Colima network profile. # ODS_MACOS_HOST_GATEWAY= # ODS_MACOS_VM_IP= # ODS_MACOS_LLM_BRIDGE_ENABLED= # ODS_MACOS_HOST_AGENT_BRIDGE_ENABLED= # ODS_NATIVE_LLAMA_PORT=8080 # Dashboard API key (generate: openssl rand -hex 32) # DASHBOARD_API_KEY= # ODS host agent key (generate: openssl rand -hex 32) — auto-generated by installer; rotating breaks host-agent authentication # ODS_AGENT_KEY= # Session-cookie signing secret. Used by dashboard-api to mint # HMAC-signed `ods-session` cookies at magic-link redemption, and # by the Hermes auth-proxy to verify them via /api/auth/verify-session. # Generate with: openssl rand -hex 32. Rotating invalidates all # currently-issued session cookies (forces re-redemption). # ODS_SESSION_SECRET= # Internal Hermes dashboard/WebSocket token. Auto-generated by the installer # and kept stable across container restarts. Rotating it requires clients with # an open Hermes tab to refresh. # HERMES_DASHBOARD_SESSION_TOKEN= # Public/custom URL and cookie domain for invite links, tunnels, and # subdomain SSO. Leave empty for normal localhost or mDNS LAN generation. # ODS_PUBLIC_URL= # Optional reverse-proxy browser URLs. The dashboard uses these exact URLs # for service launch links before falling back to the current host + port. # ODS_SERVICE_PUBLIC_URLS={"open-webui":"https://chat.example.com","comfyui":"https://comfy.example.com"} # OPEN_WEBUI_PUBLIC_URL=https://chat.example.com # COMFYUI_PUBLIC_URL=https://comfy.example.com # N8N_PUBLIC_URL=https://n8n.example.com # ODS_TALK_PUBLIC_URL=https://talk.example.com # ODS_COOKIE_DOMAIN= # Privacy Shield API key (generate: openssl rand -hex 32) - auto-generated by installer; shared between dashboard-api and privacy-shield containers # SHIELD_API_KEY= # Qdrant API key (generate: openssl rand -hex 32) # QDRANT_API_KEY= # Token Spy API key (auto-generated by installer; shared with dashboard-api) # TOKEN_SPY_API_KEY= # ═══════════════════════════════════════════════════════════════════ # Langfuse (LLM Observability) — optional, disabled by default # ═══════════════════════════════════════════════════════════════════ LANGFUSE_PORT=3006 LANGFUSE_ENABLED=false # Secrets below are auto-generated during install; leave them empty. LANGFUSE_NEXTAUTH_SECRET= LANGFUSE_SALT= LANGFUSE_ENCRYPTION_KEY= LANGFUSE_DB_PASSWORD= LANGFUSE_CLICKHOUSE_PASSWORD= LANGFUSE_REDIS_PASSWORD= LANGFUSE_MINIO_ACCESS_KEY= LANGFUSE_MINIO_SECRET_KEY= LANGFUSE_PROJECT_PUBLIC_KEY= LANGFUSE_PROJECT_SECRET_KEY= LANGFUSE_INIT_PROJECT_ID= LANGFUSE_INIT_USER_EMAIL=admin@ods.local LANGFUSE_INIT_USER_PASSWORD= # ═══════════════════════════════════════════════════════════════════ # Multi-GPU Settings (auto-populated by installer for multi-GPU) # ═══════════════════════════════════════════════════════════════════ # GPU_ASSIGNMENT_JSON_B64= # Base64-encoded GPU assignment JSON # LLAMA_SERVER_GPU_UUIDS= # GPU UUIDs for llama-server (NVIDIA, comma-separated) # LLAMA_SERVER_GPU_INDICES= # GPU indices for llama-server (AMD, comma-separated) # LLAMA_ARG_SPLIT_MODE=none # none | layer | row (NVIDIA uses layer for every multi-GPU mode) # LLAMA_ARG_TENSOR_SPLIT= # Proportional VRAM weights (e.g. 3,1) # COMFYUI_GPU_UUID= # GPU UUID for ComfyUI (NVIDIA) # WHISPER_GPU_UUID= # GPU UUID for Whisper (NVIDIA) # EMBEDDINGS_GPU_UUID= # GPU UUID for embeddings (NVIDIA) # ROCR_VISIBLE_DEVICES= # AMD GPU indices visible to ROCm (comma-separated) # VIDEO_GID=44 # Host 'video' group GID (AMD) # RENDER_GID=992 # Host 'render' group GID (AMD) # HSA_OVERRIDE_GFX_VERSION= # ROCm image only: gfx override for GPUs it was not built for # LLM_MODEL_SIZE_MB= # Approximate model size in MB # ═══════════════════════════════════════════════════════════════════ # Optional — Voice, Web UI, n8n # ═══════════════════════════════════════════════════════════════════ # Whisper model (tiny, base, small, medium, large-v3-turbo) # WHISPER_MODEL=base # Open WebUI STT settings. Installer auto-selects AUDIO_STT_MODEL by GPU: # NVIDIA → deepdml/faster-whisper-large-v3-turbo-ct2 (faster, ~1.5GB) # AMD/CPU → Systran/faster-whisper-base (~130MB) # Override to use a different model — must then run `ods restart` and # manually download the new model via: # curl -X POST --max-time 3600 http://localhost:9000/v1/models/ # AUDIO_STT_ENGINE=openai # AUDIO_STT_OPENAI_API_BASE_URL=http://whisper:8000/v1 # AUDIO_STT_OPENAI_API_KEY= # WHISPER_ACCELERATION=cpu # AUDIO_STT_MODEL=Systran/faster-whisper-base # Internal URLs used by dashboard-api and ODS Talk when running diagnostics # or voice flows from inside the Docker network. # WHISPER_URL=http://whisper:8000 # TTS_URL=http://tts:8880 # EMBEDDING_URL=http://embeddings:80 # Kokoro/Open WebUI TTS settings # AUDIO_TTS_ENGINE=openai # AUDIO_TTS_OPENAI_API_BASE_URL=http://tts:8880/v1 # AUDIO_TTS_OPENAI_API_KEY= # AUDIO_TTS_MODEL=kokoro # AUDIO_TTS_VOICE=af_heart # Legacy Kokoro TTS voice name # TTS_VOICE=en_US-lessac-medium # Open WebUI authentication (true/false). Installers default this to false for # loopback-only ODS and true when services are exposed to the network. # WEBUI_AUTH=false # Open WebUI PWA / branding name. Shown as the app title, page title, and PWA # install label (the text next to the icon on a phone's home screen). # WEBUI_NAME=ODS # Optional Open WebUI public URL — used for share links, OAuth callbacks, and # PWA install metadata. Leave empty for traditional localhost usage. After # enabling ods-proxy + mDNS, set this to the reachable chat subdomain: # http://chat..local. Override with a Tailscale Funnel / # Cloudflare Tunnel / custom domain URL when fronted by one. # WEBUI_URL=http://chat.ods.local # Device name used by mDNS announcements and as the hostname segment for # proxy/headless URLs. Letters / digits / hyphens only — short and memorable # wins (e.g. "ods", "kitchen", "lab"). # ODS_DEVICE_NAME=ods # Web search settings. Track whether SearXNG is in the compose stack — # leave false when SearXNG is disabled so Open WebUI does not show a dead toggle. # ENABLE_WEB_SEARCH=true # WEB_SEARCH_ENGINE=searxng # System timezone (used by Open WebUI and n8n) # TIMEZONE=UTC # n8n settings # N8N_HOST=localhost # n8n hostname # N8N_WEBHOOK_URL=http://localhost:5678 # n8n webhook URL (for external access) # N8N_SECURE_COOKIE=auto # false only for loopback HTTP; true for HTTPS/LAN # N8N_PROXY_HOPS=0 # set to the proxy count when using HTTPS ingress # Embedding model served by the bundled Hugging Face TEI runtime. Use a TEI- # compatible Hugging Face repository ID; GGUF/Q4 files are not supported here. # EMBEDDING_MODEL=BAAI/bge-base-en-v1.5 # Open WebUI uses EMBEDDING_MODEL unless this override is set, and reads both # each time it starts. Set this override only when the endpoint # points to a different embeddings provider/model. # RAG_EMBEDDING_MODEL= # RAG_OPENAI_API_BASE_URL=http://embeddings:80/v1 # RAG_OPENAI_API_KEY= # only for authenticated external providers # Larger models such as BAAI/bge-m3 may need a higher container memory limit. # EMBEDDINGS_MEMORY_LIMIT=4G # Image generation (ComfyUI + SDXL Lightning) # ENABLE_IMAGE_GENERATION=true # ═══════════════════════════════════════════════════════════════════ # Agent Policy Engine (APE) # ═══════════════════════════════════════════════════════════════════ # # APE audits and can enforce policy decisions for agent tool usage. # APE_PORT=7890 # APE_RATE_LIMIT_RPM=60 # APE_STRICT_MODE=false # ═══════════════════════════════════════════════════════════════════ # AMD-specific (only needed with GPU_BACKEND=amd) # ═══════════════════════════════════════════════════════════════════ # VIDEO_GID=44 # `getent group video | cut -d: -f3` # RENDER_GID=992 # `getent group render | cut -d: -f3` # AMD_INFERENCE_BACKEND=rocm # ROCm image instead of Vulkan (required for Instinct cards) # HSA_OVERRIDE_GFX_VERSION=11.0.0 # ROCm only, for a GPU the ROCm image was not built for # ROCBLAS_USE_HIPBLASLT=0 # ROCm only: 1 makes rocBLAS use hipBLASLt kernels (default 0) # ═══════════════════════════════════════════════════════════════════ # Advanced # ═══════════════════════════════════════════════════════════════════ # Host user/group IDs persisted for Docker Compose service ownership. # The installer fills these automatically; override only when container-owned # files must use a different host identity. # ODS_UID=1000 # ODS_GID=1000 # Privacy Shield settings # PII_CACHE_ENABLED=true # PII_CACHE_SIZE=1000 # PII_CACHE_TTL=300 # LOG_LEVEL=info # Dashboard API internal URLs (usually Docker-internal, not user-facing) # KOKORO_URL=http://tts:8880 # N8N_URL=http://n8n:5678 # n8n public API key for dashboard workflow install/remove (create in n8n: Settings > n8n API) # N8N_API_KEY= # NVIDIA llama-server memory limit (Docker). When unset, installers reserve # memory for the host and other ODS services, cap the result at 64G, and use # the smaller of physical RAM and Docker Desktop's VM allocation. # Set an explicit value to override the calculated limit. Remove the generated # key before rerunning the installer if Docker's memory allocation changes and # you want ODS to calculate it again. # LLAMA_SERVER_MEMORY_LIMIT=64G # llama-server CPU core limit (auto-capped during install/update) # Tune this to control how many CPU cores llama-server may use. # LLAMA_CPU_LIMIT=8.0 # ═══════════════════════════════════════════════════════════════════ # ODS Proxy (LAN reverse proxy on port 80) # ═══════════════════════════════════════════════════════════════════ # Opt-in Caddy reverse proxy that fronts dashboard / chat / API on # port 80, so `http://.local` (no port) works from any LAN # device. Without this, services bind to 127.0.0.1 and `ods.local` # resolves to a port that's not open. # Enable: `ods enable ods-proxy`. See docs/ODS-PROXY.md. # # ODS_PROXY_PORT=80 # Host port (standard HTTP) # ODS_PROXY_TLS_PORT=443 # HTTPS port (deferred; HTTP only in v1) # ODS_PROXY_BIND=0.0.0.0 # LAN-exposed by default — that's the point # Pixel core agent (qualified Linux hosts; included with ODS) # ═══════════════════════════════════════════════════════════════════ # ODS offers Pixel as its core conversational experience on Ubuntu 24.04 or Debian 12 hosts running PID1 systemd. # ODS's broader Linux, macOS, and Windows support is unchanged: unsupported # hosts use Hermes. Pixel's ODS-only source-available grant is in # vendor/pixel/LICENSE.md. No separate acknowledgement is required. # # ENABLE_PIXEL=auto # auto, true (--pixel), or false (--no-pixel) # PIXEL_SOURCE_URL=bundled # local ODS bundle; no private Git access # PIXEL_SOURCE_REF=2ef78e7067211a198748c5499ed5a0261f4b48b6 # ODS-bundled Pixel 4.3.31 source # PIXEL_WEB_SEARCH_PROVIDER=parallel-free # Optional explicit choice; existing onboarding is preserved when omitted. Also accepts searxng. # PIXEL_GATEWAY_PORT=18789 # Fresh-install loopback port; retain the selected value on reinstall # PIXEL_MODEL_RELAY_PORT=4006 # Pixel-only authenticated model path; host loopback only # PIXEL_SOURCE_DIR= # owner-controlled parent for a local dev checkout # # Generated values below are installer-owned. Do not publish or hand-edit them. # PIXEL_OPENWEBUI_KEY= # narrow edge-only bearer token # PIXEL_MODEL_RELAY_KEY= # separate installer-generated Pixel model bearer token # PIXEL_INGRESS_RUNTIME_DIR=/run/ods-pixel # PIXEL_PREVIEW_RUNTIME_DIR=/run/ods-pixel-preview # PIXEL_INGRESS_GID= # numeric ods-pixel group GID # PIXEL_PREVIEW_PORT=9437 # isolated loopback static preview origin # PIXEL_INFERENCE_PORT=4005 # optional inference sharing; loopback only, disabled by default # Hermes Agent (Remote-capable Chat + Generalist Agent) # ═══════════════════════════════════════════════════════════════════ # Hermes Agent (Nous Research, MIT) — chat-first generalist agent with # persistent memory, autonomous skill creation, and 70+ tools. ODS # Server runs the upstream image pinned by version and points it at the # local LLM. Browser UI ships in the upstream image (port 9119). # Enable: `ods enable hermes`. Owner-card users reach the mobile ODS # Talk portal at http://talk..local/talk; advanced users can still # reach Hermes at http://hermes..local (owner-card gating is optional). # Hermes itself is internal-only — # there's no HERMES_PORT knob in this stack. # # HERMES_LLM_BASE_URL=http://llama-server:8080/v1 # OpenAI-compat endpoint # HERMES_LLM_API_KEY=sk-ods-hermes-local # Dummy (OpenAI SDK requires non-empty) # HERMES_AGENT_IMAGE=nousresearch/hermes-agent:v2026.9.24@sha256:fca358f12efd65bfaaca05884166f15c0e2788375ca30d77061ac1ebc96452b7 # Upstream Hermes image # HERMES_AGENT_IMAGE_FALLBACK= # Optional explicit fallback if upstream retags # HERMES_LANGUAGE=en # UI language # SEARXNG_URL=http://searxng:8080 # Hermes web-search backend # (No HERMES_MODEL_NAME — the model lives in /opt/data/config.yaml, # not in env. Edit the file after first start to switch models.) # # Optional Hermes WhatsApp gateway. Disabled by default; ODS's Hermes # config pins WhatsApp's internal bridge to 3010 so it does not collide with # Open WebUI's host port 3000 when users intentionally enable WhatsApp. # WHATSAPP_ENABLED=false # WHATSAPP_MODE=self-chat # WHATSAPP_ALLOWED_USERS=15551234567 # WHATSAPP_REQUIRE_MENTION= # WHATSAPP_FREE_RESPONSE_CHATS= # WHATSAPP_REPLY_PREFIX= # # Hermes is reached on the LAN via ods-hermes-proxy (Caddy sidecar) which # opens Hermes directly by default. Set HERMES_REQUIRE_OWNER_CARD=true to # require a signed ODS session through dashboard-api's verify endpoint. # Direct Hermes port is NOT bound to the host — only the proxy is LAN-facing. # HERMES_REQUIRE_OWNER_CARD=false # Optional owner-card / guest-session gate # HERMES_PROXY_PORT=9120 # LAN entry — what users actually browse to # HERMES_PROXY_UPSTREAM=ods-hermes:9119 # Where the proxy forwards (internal DNS) # ODS_AUTH_UPSTREAM=ods-dashboard-api:3002 # Where forward_auth verifies sessions # HERMES_PROXY_AUTH_DOCS_URL= # Optional help link on the auth-required page # Tailscale (Remote Access) # ═══════════════════════════════════════════════════════════════════ # Optional remote-access via Tailscale's mesh VPN. Generate an auth # key at https://login.tailscale.com/admin/settings/keys and paste # below. Once joined the device is reachable as ..ts.net # from any other tailnet member. # # IMPORTANT: joining the tailnet alone isn't enough. For the device to # actually answer HTTP at .tail-xxxxx.ts.net, the host has to # be listening for non-loopback traffic. That means: # 1. ods-proxy is enabled (Caddy fielding port 80 + routing /chat, # /api/*, /auth/* to backends) # 2. BIND_ADDRESS=0.0.0.0 in this .env (loopback-only services don't # accept tailnet packets even with network_mode: host) # See docs/TAILSCALE.md for the full prerequisites and architecture. # # TS_AUTHKEY is consumed exactly once on first join. After that the # tailscale daemon caches the node key in data/tailscale/, so you can # rotate or delete the auth key in the Tailscale admin. # # TS_AUTHKEY=tskey-auth-xxxxxxxxxxxxxxxxxxxxxx # TS_HOSTNAME= # Defaults to ODS_DEVICE_NAME # TS_EXTRA_ARGS= # Optional, e.g. --advertise-tags=tag:ods