# Open WebUI Deployment Plan > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Deploy Open WebUI on hf-pdocker-01 with Ollama + Anthropic Claude backends, publicly accessible at `open.hobbs.farm`. **Architecture:** Single-container Compose service on hf-pdocker-01. Traefik file-based dynamic config for HTTPS routing. NAS-backed persistent storage. Prometheus blackbox probes for monitoring. **Tech Stack:** Open WebUI (ghcr.io/open-webui/open-webui:main), Traefik v3.6 (file provider), Prometheus blackbox exporter. **Spec:** `docs/superpowers/specs/2026-03-11-openwebui-design.md` --- ## Chunk 1: Create Files and Deploy ### Task 1: Create Compose File **Files:** - Create: `compose/hf-pdocker-01/openwebui/docker-compose.yml` - [ ] **Step 1: Create the compose file** ```yaml services: open-webui: image: ghcr.io/open-webui/open-webui:main container_name: open-webui restart: unless-stopped ports: - "3010:8080" env_file: - .env environment: - TZ=America/Chicago - OLLAMA_BASE_URL=http://192.168.86.196:11434 volumes: - /mnt/docker-data/configs/openwebui:/app/backend/data mem_limit: 1G memswap_limit: 1G labels: - "com.centurylinklabs.watchtower.enable=false" healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:8080/health || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 60s logging: driver: "json-file" options: max-size: "50m" max-file: "3" ``` ### Task 2: Create Traefik Dynamic Config **Files:** - Create: `stacks/traefik/dynamic/openwebui.yml` - [ ] **Step 1: Create the Traefik dynamic route file** ```yaml http: routers: openwebui: rule: "Host(`open.hobbs.farm`)" entryPoints: - websecure service: openwebui tls: certResolver: letsencrypt openwebui-http: rule: "Host(`open.hobbs.farm`)" entryPoints: - web middlewares: - openwebui-https-redirect service: openwebui middlewares: openwebui-https-redirect: redirectScheme: scheme: https permanent: true services: openwebui: loadBalancer: servers: - url: "http://192.168.86.192:3010" ``` ### Task 3: Deploy to hf-pdocker-01 Uses `docker-swarm-ops` agent. All steps run on hf-pdocker-01 via SSH. - [ ] **Step 1: Create data directory on NAS** ```bash ssh glyptic@192.168.86.192 "sudo mkdir -p /mnt/docker-data/configs/openwebui" ``` - [ ] **Step 2: Create compose directory on NAS** ```bash ssh glyptic@192.168.86.192 "sudo mkdir -p /mnt/docker-data/compose/hf-pdocker-01/openwebui" ``` - [ ] **Step 3: Generate WEBUI_SECRET_KEY and create .env file** ```bash SECRET=$(openssl rand -hex 32) # Get ANTHROPIC_API_KEY from existing ai-agents .env on NAS API_KEY=$(ssh glyptic@192.168.86.192 "grep ANTHROPIC_API_KEY /mnt/docker-data/compose/hf-pdocker-01/ai-agents/.env | cut -d= -f2") ssh glyptic@192.168.86.192 "cat > /mnt/docker-data/compose/hf-pdocker-01/openwebui/.env << EOF ANTHROPIC_API_KEY=$API_KEY WEBUI_SECRET_KEY=$SECRET EOF" ``` - [ ] **Step 4: SCP compose file to NAS** ```bash scp compose/hf-pdocker-01/openwebui/docker-compose.yml glyptic@192.168.86.192:/mnt/docker-data/compose/hf-pdocker-01/openwebui/docker-compose.yml ``` - [ ] **Step 5: SCP Traefik dynamic config to NAS** ```bash scp stacks/traefik/dynamic/openwebui.yml glyptic@192.168.86.192:/mnt/docker-data/traefik/dynamic/openwebui.yml ``` - [ ] **Step 6: Pull image and start container** ```bash ssh glyptic@192.168.86.192 "cd /mnt/docker-data/compose/hf-pdocker-01/openwebui && docker compose pull && docker compose up -d" ``` - [ ] **Step 7: Verify container health** ```bash ssh glyptic@192.168.86.192 "docker ps --filter name=open-webui --format 'table {{.Names}}\t{{.Status}}'" ``` Expected: `open-webui Up ... (healthy)` (may take up to 60s for healthcheck) - [ ] **Step 8: Verify internal access** ```bash ssh glyptic@192.168.86.192 "curl -sf -o /dev/null -w '%{http_code}' http://localhost:3010" ``` Expected: `200` - [ ] **Step 9: Verify Traefik picked up the route** ```bash curl -sf -o /dev/null -w '%{http_code}' https://open.hobbs.farm ``` Expected: `200` (Traefik auto-reloads file-based config) - [ ] **Step 10: Verify Ollama connectivity from container** ```bash ssh glyptic@192.168.86.192 "docker exec open-webui curl -sf http://192.168.86.196:11434/api/tags | head -c 200" ``` Expected: JSON response listing available Ollama models (llava:13b) ## Chunk 2: Monitoring and Documentation ### Task 4: Add Prometheus Blackbox Probes **Files:** - Modify: `stacks/monitoring/prometheus.yml` - [ ] **Step 1: Add internal probe to http-pdocker01 job** Add `- http://192.168.86.192:3010 # Open WebUI` to the `http-pdocker01` targets list (after the Alertmanager line, line 70). - [ ] **Step 2: Add external probe to http-external job** Add `- https://open.hobbs.farm # Open WebUI` to the `http-external` targets list (after the Gitea line, line 158). - [ ] **Step 3: SCP updated prometheus.yml to NAS** ```bash scp stacks/monitoring/prometheus.yml glyptic@192.168.86.192:/mnt/docker-data/configs/prometheus/prometheus.yml ``` - [ ] **Step 4: Hot-reload Prometheus** ```bash ssh glyptic@192.168.86.192 "curl -X POST http://localhost:9095/-/reload" ``` - [ ] **Step 5: Verify probes are up** ```bash ssh glyptic@192.168.86.192 "curl -s 'http://localhost:9095/api/v1/targets?state=active' | python3 -c \"import sys,json; targets=json.load(sys.stdin)['data']['activeTargets']; [print(t['labels'].get('instance','')) for t in targets if 'open' in t['labels'].get('instance','').lower()]\"" ``` Expected: Two lines showing `http://192.168.86.192:3010` and `https://open.hobbs.farm` ### Task 5: Update CLAUDE.md **Files:** - Modify: `CLAUDE.md` - [ ] **Step 1: Add Open WebUI to hf-pdocker-01 service list** Add `├── [COMPOSE] Open WebUI (:3010) -- LLM chat UI (Ollama + Claude)` to the hf-pdocker-01 section. - [ ] **Step 2: Add to internal services list** Add `- Open WebUI: :3010` under hf-pdocker-01 internal services. - [ ] **Step 3: Add to public services list** Add `- Open WebUI: \`open.hobbs.farm\`` under Public Services. ### Task 6: Update MEMORY.md **Files:** - Modify: `/home/glyptic/.claude/projects/-mnt-c-Users-Jeremy-projects-docker/memory/MEMORY.md` - [ ] **Step 1: Add Open WebUI memory entry** Add section with deployment details: node, port, compose path, LLM backends, Traefik route, data path. ### Task 7: Update Wiki - [ ] **Step 1: Launch documentation-keeper agent (background)** Update wiki with new Open WebUI service documentation. ### Task 8: Commit - [ ] **Step 1: Commit all new/modified files** ```bash git add compose/hf-pdocker-01/openwebui/docker-compose.yml stacks/traefik/dynamic/openwebui.yml stacks/monitoring/prometheus.yml CLAUDE.md git commit -m "infra: deploy Open WebUI on hf-pdocker-01 with Ollama + Claude backends" ```