Files
knowledge-base/decisions/2026-06-22-open-webui-deploy.md

6.3 KiB
Raw Blame History

date, type, status, tags
date type status tags
2026-06-22 decision done
homelab
proxmox
open-webui
omniroute
npm
ai

Open WebUI на home lab — веб-клиент «как ChatGPT» поверх OmniRoute

Зачем

Олегу нужен удобный веб-интерфейс для работы с ИИ на домашнем сервере (не Telegram-бот, не голый CLI). Решение: Open WebUI — поверх уже имеющегося OmniRoute (OpenAI-совместимый шлюз, 145 моделей вкл. cc/claude-opus-4-8 через Max).

NB: на клиентской коробке Александра Open WebUI наоборот выкинут — там мозг openclaw со своим веб-UI, а железо слабое (Sandy Bridge i3). Open WebUI оправдан только на мощном home lab. См. ../projects/dttb/proxmox-inventory.

Что развёрнуто (LXC 142)

  • LXC 142 open-webui на Proxmox 10.0.0.250: Debian 12, unprivileged + nesting=1,keyctl=1 (для Docker), 2 vCPU / 2 ГБ / 12 ГБ.
  • rootfs на хранилище work (11.5 ТБ), НЕ local-lvm (тот забит на 93%).
  • Статика 10.0.0.142, DNS контейнера = 1.1.1.1 (обойти FakeIP-перехват от роутера 10.0.0.1 при pull образов и загрузке embedding-модели).
  • Docker 20.10 (из Debian-репо), контейнер ghcr.io/open-webui/open-webui:main v0.9.6, -p 3000:8080, volume open-webui, restart=always, onboot=1.
  • Подключение к OmniRoute: OPENAI_API_BASE_URL=http://10.0.0.179:20128/v1, OPENAI_API_KEY=sk-omniroute (LAN-доступ к OmniRoute без авторизации → ключ любой), ENABLE_OLLAMA_API=false.

Публикация

  • Spaceweb A-запись chat → 176.62.183.186 (скрипт snippets/spaceweb-dns-api.py add-a dttb.ru chat …).
  • NPM (10.0.0.195:81) proxy host id39 chat.dttb.ru10.0.0.142:3000, WebSockets on, Force SSL, LE cert id129 (до 2026-09-20).
  • Локально *.dttb.ru уже резолвится в 10.0.0.195 (hairpin-перехват DNS на роутере) → по LAN/NetBird работает сразу, без правки DNS.

Грабли

  1. NPM v2.14 cert-create: при provider:letsencrypt тело принимает только meta:{} (пустой). С letsencrypt_email/agree/dns_challenge400 data/meta must NOT have additional properties. Email берётся из аккаунта NPM. (Совпало с заметкой по коробке Александра.)
  2. DNS-распространение: после add-a Google DoH видит запись ~через 5 мин, Cloudflare держит негативный кэш до 10 мин (SOA min TTL 600). LE запрашивает авторитативные NS напрямую → серт выпускается, как только Google увидел. Проверка только через DoH (локальный dig/getent перехватываются роутером).
  3. Первый старт Open WebUI: тянет embedding-модель с HuggingFace (~1 ГБ, 30 файлов) — из РФ медленно, стартап висит на «Fetching 30 files» пару минут. Это нормально; DNS 1.1.1.1 помогает. RAG-эмбеддинги можно позже переключить на OmniRoute.
  4. Open WebUI signup: первый зарегистрированный = admin. Открытую регистрацию выключать в Admin Panel → Settings (env ENABLE_SIGNUP не действует — persistent config хранится в БД и перебивает env).
  5. Max-кап: cc/claude-opus-4-8 делит 5-часовой кап Max с german/openclaw/swarmclaw/code-server → при нагрузке 400 «out of extra usage» (транзиентно). Для тяжёлых сессий fallback kr/claude-sonnet-4.5 (free).
  6. Ключ OmniRoute = пустой, НЕ dummy (важно!). Open WebUI сначала показывал 0 моделей. Причина: домашний OmniRoute с непустым неизвестным ключом (sk-omniroute) отдаёт {"data":[]} (скоупит по ключу→0 провайдеров), а с отсутствующим/пустым auth — полный каталог (LAN-доверие). Open WebUI всегда шлёт Authorization: Bearer <key>. Фикс: ключ коннекта = пустая строка (OPENAI_API_KEYS:[""]). German/openclaw ходят так же (без auth); найденный в их конфигах ork_VQo75… — это inbound-ключ openclaw, к OmniRoute-авторизации отношения не имеет (тоже даёт 0).

Настройка Open WebUI (через API, токен = signin админом)

  • Коннект: POST /openai/config/update {ENABLE_OPENAI_API:true, OPENAI_API_BASE_URLS:["http://10.0.0.179:20128/v1"], OPENAI_API_KEYS:[""], OPENAI_API_CONFIGS:{}}. NB: POST /openai/config (без /update) уходит в passthrough-роут → ошибка «Direct API passthrough is disabled».
  • Дефолтная модель: POST /api/v1/configs/models {"DEFAULT_MODELS":"cc/claude-opus-4-8", ...}. Персистится в БД, переживает рестарт. Публичный /api/config поле default_models НЕ отдаёт в v0.9.6 — это норма, не индикатор.
  • Регистрация: ENABLE_SIGNUP=false по умолчанию (проверять GET /api/v1/auths/admin/config).
  • Проверка end-to-end: POST /api/chat/completions {model:"cc/claude-opus-4-8", messages:[...], stream:false} → ответ от Opus 4.8.
  • openapi.json отключён (0 байт) — интроспекции нет, эндпоинты выше зафиксированы вручную.

Команды

# контейнер
sshpass -p '1qaz!QAZ' ssh root@10.0.0.250 "pct exec 142 -- docker ps"
sshpass -p '1qaz!QAZ' ssh root@10.0.0.250 "pct exec 142 -- docker logs --tail 30 open-webui"
# обновление образа
pct exec 142 -- bash -lc 'docker pull ghcr.io/open-webui/open-webui:main && docker rm -f open-webui && <docker run ...>'