Files
hermes-skills/skills/devops/open-webui/SKILL.md
T

9.3 KiB

name, description, version, tags
name description version tags
open-webui Deploy, configure, and upgrade Open WebUI on app1 — vision support, image generation, RAG, model management, and admin-ai backend integration. 1.0.0
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

User → Caddy (ai.itpropartner.com) → localhost:3000 → Open WebUI Docker
                                                          ↓
                                              admin-ai.itpropartner.com/v1 (LiteLLM)
                                                          ↓
                                              100+ models across providers

Deployment

# 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=<admin-ai-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

# Test connectivity from inside the container
docker exec openwebui curl -s <base_url>/v1/models -H 'Authorization: Bearer <key>' | 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

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:

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.

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)

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

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': '<group-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:<port>/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

cd /docker/openwebui && docker compose down && docker compose up -d
# or for quick restart:
docker restart openwebui

Upgrades

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.