e0d1c44137
The 2026-09-06 headscale cutover retired irv-ml1's wg0 tunnel IP 10.100.79.3 (now 10.6.110.50). Repointed all LIVE canonical refs to the DNS NAME so the next move can't re-break them: homepage.href/siteMonitor labels across 25 stack composes, load-bearing env defaults (asset-engine INFERENCE_HOST, open-webui AUDIO_TTS_OPENAI_API_BASE_URL, skaldsong SKALDSONG_TTS_BASE_URL, zonos-gateway ZONOS_URL, dia), homepage services.yaml manual cards (Voice Design Studio, IRV-ML1), and servers/irv-ml1/ssh-target. Updated the stale 'WG tunnel' comment to the mesh reality. Left as-is: README curl-examples and .env.example comments (docs), and historical mentions in CLAUDE.md/persistent-memory. NOTE: applying the label repoints to the RUNNING irv-ml1 containers needs a recreate per service (labels read at creation); deployed .env values are separate from these canonical defaults.
123 lines
6.7 KiB
YAML
123 lines
6.7 KiB
YAML
# open-webui — evaluation chat frontend over the LiteLLM gateway, on esh-docker-vm.
|
|
#
|
|
# WHY THIS EXISTS (bake-off against lobe-chat, 2026-08-21)
|
|
# Lobe's config model does not survive a fleet that changes daily: its model
|
|
# list is a static env string that never auto-discovers (it rotted in BOTH
|
|
# directions — missed `sec`/`sec-reasoning` going in, kept retired `char-rp`
|
|
# names that 400 on click), and half its config (TTS service/model/voice)
|
|
# lives in each browser's local store, so "configured" is a property of
|
|
# whoever's laptop rather than of the deploy. Open WebUI is env-declarative and
|
|
# auto-tracks the gateway roster. This stack stands up PARALLEL to lobe-chat
|
|
# (Lobe on :3210, this on :3211); nothing about Lobe changes until/unless the
|
|
# operator retires it. The June-2026 weight objection (1,825 MB vs 143 MB) is
|
|
# moot here: esh-docker-vm has ~138 GB free.
|
|
#
|
|
# THE DEAL-SEALER — ENABLE_PERSISTENT_CONFIG=False (see .env)
|
|
# Default is True, and under True env vars are read ONCE on first boot,
|
|
# written to the DB, then ignored forever — so edit-env-and-bounce silently
|
|
# does nothing. We set it False so the deploy is the single source of config
|
|
# truth: every knob below is re-read from env on each boot, and a change made
|
|
# in the Admin UI does NOT survive a restart. Verified both directions at
|
|
# deploy (G1). ⚠️ Open upstream bugs touch this flag (open-webui #20830 Redis
|
|
# cache — N/A, we use no Redis; #15505; #21839) — re-verify after image bumps.
|
|
#
|
|
# CREDENTIAL POSTURE (G6 — chosen, not inherited)
|
|
# Purpose-minted LiteLLM virtual key `key_alias: open-webui-esh`, scoped to the
|
|
# `all-proxy-models` access group (reaches EVERYTHING incl. paid passthroughs —
|
|
# GLM/Kimi/gen-frontier) per the operator's standing posture, BUT capped with a
|
|
# `max_budget` ceiling (unlike lobe-chat-esh which is uncapped). A paid call
|
|
# from this UI spends real vendor credits until the cap trips. Signup is turned
|
|
# OFF after the first/admin account is created, so the surface is not open-
|
|
# registration on the LAN. Secrets live in the vault, never in git:
|
|
# secret get esh-docker-vm/open-webui-litellm-key -> OPENAI_API_KEY
|
|
# secret get esh-docker-vm/open-webui-secret-key -> WEBUI_SECRET_KEY
|
|
# secret get esh-docker-vm/open-webui-admin -> lkraven admin cred state
|
|
#
|
|
# TTS (G4 — tts-dev owns verification; env knobs set here)
|
|
# Routed DIRECT at the fleet dots gateway http://10.100.79.3:8198/v1, NOT
|
|
# through LiteLLM. Rationale (agreed with tts-dev): :8198 is itself the swap-
|
|
# proof switchboard — engines swap behind it — so LiteLLM would add only a hop
|
|
# and a wrong `audio/mpeg` content-type stamp; direct needs no gateway key on
|
|
# the audio path. Reversible: flip AUDIO_TTS_OPENAI_API_BASE_URL to the gateway
|
|
# + `ext-tts` if audio spend/log visibility is ever wanted. The five AUDIO_TTS_*
|
|
# vars are tts-dev's to tune (model/voice); base URL + engine are settled.
|
|
|
|
name: open-webui
|
|
|
|
services:
|
|
open-webui:
|
|
image: ghcr.io/open-webui/open-webui:${OPENWEBUI_TAG:-main}
|
|
container_name: ${OPENWEBUI_CONTAINER:-open-webui}
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${OPENWEBUI_PORT:-3211}:8080"
|
|
environment:
|
|
# --- The deal-sealer: deploy is the single source of config truth. ---
|
|
- ENABLE_PERSISTENT_CONFIG=${ENABLE_PERSISTENT_CONFIG:-False}
|
|
- ENV=${OPENWEBUI_ENV:-prod}
|
|
- WEBUI_NAME=${WEBUI_NAME:-PFI Open WebUI}
|
|
- WEBUI_URL=${WEBUI_URL:-http://10.0.50.45:3211}
|
|
# --- Auth / signup posture (G6). Signup is flipped False post-admin. ---
|
|
- WEBUI_AUTH=${WEBUI_AUTH:-True}
|
|
- WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY:?set in .env, from the vault}
|
|
- ENABLE_SIGNUP=${ENABLE_SIGNUP:-False}
|
|
- ENABLE_LOGIN_FORM=${ENABLE_LOGIN_FORM:-True}
|
|
- DEFAULT_USER_ROLE=${DEFAULT_USER_ROLE:-pending}
|
|
# NOTE: the env var is ENABLE_API_KEYS (plural) in Open WebUI v0.11.0
|
|
# (config.py: os.getenv('ENABLE_API_KEYS','False')). The singular form is
|
|
# inert — a deploy that sets ENABLE_API_KEY silently leaves key-mint 403.
|
|
- ENABLE_API_KEYS=${ENABLE_API_KEYS:-True}
|
|
# --- Model source: the LiteLLM gateway, no pins (G2 auto-tracks). ---
|
|
- ENABLE_OPENAI_API=${ENABLE_OPENAI_API:-True}
|
|
- OPENAI_API_BASE_URL=${OPENAI_API_BASE_URL:-http://10.250.50.70:4000/v1}
|
|
- OPENAI_API_KEY=${OPENAI_API_KEY:?set in .env, from the vault}
|
|
# Ollama is banned fleet-wide; keep the client from probing localhost:11434.
|
|
- ENABLE_OLLAMA_API=${ENABLE_OLLAMA_API:-False}
|
|
# --- Background task model (G5): pin it or an unpinned default hammers a
|
|
# name the gateway does not serve and fills logs with 4xx. External
|
|
# (OpenAI-type) models use TASK_MODEL_EXTERNAL. summarizer = gen seat
|
|
# at temp 0, the right fit for auto-title/tag/query-rewrite. ---
|
|
- TASK_MODEL_EXTERNAL=${TASK_MODEL_EXTERNAL:-summarizer}
|
|
# --- RAG embeddings through the gateway (fleet-consistent; avoids a boot-
|
|
# time HuggingFace download of the default local sentence-transformer). ---
|
|
- RAG_EMBEDDING_ENGINE=${RAG_EMBEDDING_ENGINE:-openai}
|
|
- RAG_EMBEDDING_MODEL=${RAG_EMBEDDING_MODEL:-qwen3-embedding}
|
|
- RAG_OPENAI_API_BASE_URL=${RAG_OPENAI_API_BASE_URL:-http://10.250.50.70:4000/v1}
|
|
- RAG_OPENAI_API_KEY=${OPENAI_API_KEY:?set in .env, from the vault}
|
|
# --- TTS (G4): direct at the dots gateway, engine + base URL settled;
|
|
# model/voice are tts-dev's to tune. Seat is LAN/WG-only, no auth. ---
|
|
- AUDIO_TTS_ENGINE=${AUDIO_TTS_ENGINE:-openai}
|
|
- AUDIO_TTS_OPENAI_API_BASE_URL=${AUDIO_TTS_OPENAI_API_BASE_URL:-http://irv-ml1.nh3.internal:8198/v1}
|
|
- AUDIO_TTS_OPENAI_API_KEY=${AUDIO_TTS_OPENAI_API_KEY:-sk-no-auth-lan-seat}
|
|
- AUDIO_TTS_MODEL=${AUDIO_TTS_MODEL:-tts-1}
|
|
- AUDIO_TTS_VOICE=${AUDIO_TTS_VOICE:-nova}
|
|
# --- Telemetry off. ---
|
|
- ANONYMIZED_TELEMETRY=${ANONYMIZED_TELEMETRY:-False}
|
|
- DO_NOT_TRACK=${DO_NOT_TRACK:-True}
|
|
- SCARF_NO_ANALYTICS=${SCARF_NO_ANALYTICS:-True}
|
|
volumes:
|
|
- open-webui_data:/app/backend/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "python3 -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:8080/health').status==200 else 1)\" || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 120s
|
|
networks:
|
|
- tnet
|
|
labels:
|
|
- homepage.group=AI - Gateways & Chat
|
|
- homepage.name=Open WebUI (esh)
|
|
- homepage.icon=mdi-chat-question
|
|
- homepage.description=Env-declarative chat frontend over the LiteLLM gateway (eval vs Lobe)
|
|
- homepage.href=http://10.0.50.45:${OPENWEBUI_PORT:-3211}
|
|
|
|
volumes:
|
|
open-webui_data:
|
|
name: open-webui_data
|
|
|
|
networks:
|
|
tnet:
|
|
name: traefik-net
|
|
external: true
|