--- name: open-webui description: Deploy, configure, and upgrade Open WebUI on app1 — vision support, image generation, RAG, model management, and admin-ai backend integration. version: 1.0.0 tags: [open-webui, ai, chat, vision, rag, app1, admin-ai, docker] --- # Open WebUI Self-hosted AI chat interface at `http://ai.itpropartner.com` running on app1 (152.53.36.131). ## Architecture ```text User → Caddy (ai.itpropartner.com) → localhost:3000 → Open WebUI Docker ↓ admin-ai.itpropartner.com/v1 (LiteLLM) ↓ 100+ models across providers ``` ## Deployment ```bash # On app1: /docker/openwebui/docker-compose.yml services: openwebui: image: ghcr.io/open-webui/open-webui:latest container_name: openwebui restart: unless-stopped ports: - "127.0.0.1:3000:8080" environment: - OPENAI_API_BASE_URL=https://admin-ai.itpropartner.com/v1 - OPENAI_API_KEY= - WEBUI_NAME=IT Pro Partner AI volumes: - openwebui_data:/app/backend/data volumes: openwebui_data: external: true ``` ## Models 100+ models through admin-ai. Vision-capable: claude-sonnet-4-6, gemini-flash-latest, gemini-pro-latest. ## Troubleshooting: No Models Showing Up When OpenWebUI shows an empty model list, the API connection is failing. The DB values for `openai.api_base_urls` and `openai.api_keys` override docker-compose env vars after they've been set via the Admin UI. ### Quick diagnostic ```bash # Test connectivity from inside the container docker exec openwebui curl -s /v1/models -H 'Authorization: Bearer ' | head -c 200 # Check current DB config sqlite3 /var/lib/docker/volumes/openwebui_data/_data/webui.db \ "SELECT key, substr(value, 1, 120) FROM config WHERE key IN ('openai.api_base_urls', 'openai.api_keys')" ``` ### Common misconfigurations - **`http://litellm:4000/v1`** — LiteLLM runs on core (netcup), not locally on app1. `litellm` hostname does NOT resolve from app1's Docker network. Use `https://admin-ai.itpropartner.com/v1` instead. - **Wrong/missing API key** — The key stored in `openai.api_keys` must be a valid LiteLLM key with access to `GET /v1/models`. ### Fix ```python import sqlite3, json, time db = sqlite3.connect('/var/lib/docker/volumes/openwebui_data/_data/webui.db') # Fix base URL db.execute("UPDATE config SET value = ?, updated_at = ? WHERE key = 'openai.api_base_urls'", (json.dumps(['https://admin-ai.itpropartner.com/v1']), int(time.time()))) db.commit() db.close() ``` Then restart: `docker restart openwebui` ## Enabling Vision Support (CRITICAL) Open WebUI uses `ConfigVar` environment variables — after first launch, values persist in the SQLite database and env var changes are **ignored**. Must update the DB directly: ```python import sqlite3, json, time db = sqlite3.connect('/var/lib/docker/volumes/openwebui_data/_data/webui.db') db.execute(""" UPDATE config SET value = ?, updated_at = ? WHERE key = 'models.default_metadata' """, ('{"capabilities": {"vision": true}}', int(time.time()))) db.commit() db.close() ``` Then restart: `docker restart openwebui` **Pitfall:** Setting `DEFAULT_MODEL_METADATA` in docker-compose.yml only works on FIRST launch. Subsequent restarts use the DB value. Always update both — the compose file for fresh deploys AND the DB for live instances. ## Web Search Configured via DB config keys. Open WebUI supports multiple search backends — switch between them by updating `web.search.engine` and the corresponding credentials. ### Current setup (Google PSE) ```python import sqlite3, time db = sqlite3.connect('/var/lib/docker/volumes/openwebui_data/_data/webui.db') db.execute("UPDATE config SET value = ?, updated_at = ? WHERE key = ?", ('true', int(time.time()), 'web.search.enable')) db.execute("UPDATE config SET value = ?, updated_at = ? WHERE key = ?", ('"google_pse"', int(time.time()), 'web.search.engine')) db.commit() ``` Google PSE keys are already in the DB: - `web.search.google_pse_api_key` - `web.search.google_pse_engine_id` ### Switching search engines - `"searxng"` — uses `web.search.searxng_query_url` (public instances are rate-limited; deploy your own) - `"google_pse"` — uses Google Programmable Search Engine (pre-configured, works reliably) - Other backends: brave, kagi, serpapi, tavily, etc. — each needs its own API key row ### Enabling web search in chat Users click the 🌐 toggle in the chat input to enable web search per-message. Results are injected as RAG context with inline citations. ## MCP Connectivity Open WebUI natively supports MCP Streamable HTTP connections. Add via **Admin Settings → External Tools** (UI) or directly in the SQLite DB. ### Adding an MCP server via DB ```python import sqlite3, json, time db = sqlite3.connect('/var/lib/docker/volumes/openwebui_data/_data/webui.db') row = db.execute("SELECT value FROM config WHERE key='tool_server.connections'").fetchone() current = json.loads(row[0]) if row else [] new_conn = { 'url': 'http://host.docker.internal:8899/mcp', # Use host.docker.internal for Docker→host 'type': 'mcp', # NOT 'openapi' 'auth_type': 'none', # 'none', 'bearer', or 'oauth_2.1' 'key': '', 'config': { 'enable': True, 'function_name_filter_list': '', # Leave empty to expose all tools 'access_grants': [{'principal_type': 'group', 'principal_id': '', 'permission': 'read'}] }, 'info': {'name': 'My MCP Server', 'description': '...'} } current.append(new_conn) db.execute("UPDATE config SET value = ?, updated_at = ? WHERE key = ?", (json.dumps(current), int(time.time()), 'tool_server.connections')) db.commit() ``` Then restart: `docker restart openwebui` ### MCP vs OpenAPI connection types - **MCP (Streamable HTTP):** Type `"mcp"` — stateful, tool-rich, follows MCP protocol - **OpenAPI:** Type `"openapi"` — stateless REST, follows OpenAPI spec **Pitfall:** Using `"openapi"` as the type for an MCP server URL causes an infinite loading spinner and browser console error. Always use `"mcp"` for MCP servers. ### Access Control MCP servers are admin-only to add. Grant user access via `access_grants` — assign to a group so all users in that group get the tools. ### Docker→host addressing When Open WebUI runs in Docker and the MCP server is on the host, use `http://host.docker.internal:/mcp` instead of `localhost`. Configured via admin-ai → Gemini Imagen: - Engine: openai (OpenAI-compatible API) - Model: `gemini/imagen-4.0-generate-001` - Size: 2048x2048 Enabled in DB config: `('image_generation.enable', 'true')` ## Document Upload (RAG) PDFs, files, and documents are processed through the built-in RAG pipeline: - Embedding model: `sentence-transformers/all-MiniLM-L6-v2` (downloaded from HuggingFace on first use) - Vector DB: ChromaDB (SQLite-backed, local) - PDF extraction: page-based mode, PDF image extraction enabled - Chunk size: 1000, overlap: 100 ## DB Config Reference Database: `/var/lib/docker/volumes/openwebui_data/_data/webui.db` Schema: `config(key TEXT PRIMARY KEY, value JSON, updated_at BIGINT)` Key rows to know about: | key | purpose | |---|---| | `models.default_metadata` | Vision, image_gen capabilities | | `image_generation.enable` | Image gen toggle | | `image_generation.model` | Active image gen model | | `openai.api_base_urls` | Backend API URL | | `openai.api_keys` | Backend API key | | `user.permissions` | Feature flags per role | ## Restart ```bash cd /docker/openwebui && docker compose down && docker compose up -d # or for quick restart: docker restart openwebui ``` ## Upgrades ```bash cd /docker/openwebui docker compose pull docker compose down && docker compose up -d # Re-apply vision metadata (config may reset on major upgrades) ``` ## Pitfalls - **ConfigVar persistence:** After first launch, env vars like `DEFAULT_MODEL_METADATA` are ignored. Always update the SQLite DB directly for running instances. Set both env AND DB for fresh deploys. - **Container name conflict:** `docker compose down` sometimes leaves the container name reserved. Use `docker rm -f openwebui` before `docker compose up`. - **No sqlite3 in container:** Use Python `sqlite3` module on the host, pointing at the Docker volume path. - **Model list refresh:** Models from admin-ai are fetched at startup. If admin-ai models change, restart Open WebUI to refresh. - **MCP type mismatch:** Using `"openapi"` connection type for an MCP server crashes the frontend with an infinite loading spinner. Always use `"mcp"`. - **Web search engine switch:** Google PSE is pre-configured and reliable. Public SearXNG instances are rate-limited — deploy your own if you need SearXNG. - **`http://litellm:4000/v1` won't resolve:** LiteLLM runs on core (netcup), not locally on app1. The `litellm` hostname doesn't resolve from app1's Docker network. Always use `https://admin-ai.itpropartner.com/v1` as the base URL. This is the most common cause of "no models showing up." - **UI overrides env vars in DB:** `openai.api_base_urls` and `openai.api_keys` set via Admin UI persist in the SQLite DB and override docker-compose environment variables. When models disappear, check the DB values first, not the compose file.