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

50 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
date: 2026-06-22
type: decision
status: done
tags: [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.ru``10.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_challenge``400 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 байт) — интроспекции нет, эндпоинты выше зафиксированы вручную.
## Команды
```bash
# контейнер
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 ...>'
```