8.1 KiB
8.1 KiB
date, type, status, tags
| date | type | status | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|
| 2026-06-22 | decision | done |
|
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:mainv0.9.6,-p 3000:8080, volumeopen-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.
Грабли
- NPM v2.14 cert-create: при
provider:letsencryptтело принимает толькоmeta:{}(пустой). Сletsencrypt_email/agree/dns_challenge→400 data/meta must NOT have additional properties. Email берётся из аккаунта NPM. (Совпало с заметкой по коробке Александра.) - DNS-распространение: после add-a Google DoH видит запись ~через 5 мин, Cloudflare держит негативный кэш до 10 мин (SOA min TTL 600). LE запрашивает авторитативные NS напрямую → серт выпускается, как только Google увидел. Проверка только через DoH (локальный
dig/getent перехватываются роутером). - Первый старт Open WebUI: тянет embedding-модель с HuggingFace (~1 ГБ, 30 файлов) — из РФ медленно, стартап висит на «Fetching 30 files» пару минут. Это нормально; DNS 1.1.1.1 помогает. RAG-эмбеддинги можно позже переключить на OmniRoute.
- Open WebUI signup: первый зарегистрированный = admin. Открытую регистрацию выключать в Admin Panel → Settings (env
ENABLE_SIGNUPне действует — persistent config хранится в БД и перебивает env). - Max-кап:
cc/claude-opus-4-8делит 5-часовой кап Max с german/openclaw/swarmclaw/code-server → при нагрузке 400 «out of extra usage» (транзиентно). Для тяжёлых сессий fallbackkr/claude-sonnet-4.5(free). - Ключ 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 байт) — интроспекции нет, эндпоинты выше зафиксированы вручную.
Способности (что «умеет»)
Open WebUI = пассивный «кабинет подумать/найти/написать», НЕ исполнитель на инфре (это German/Антошка).
- Веб-поиск: DuckDuckGo (без ключа).
POST /api/v1/retrieval/config/update {web:{ENABLE_WEB_SEARCH:true, WEB_SEARCH_ENGINE:"duckduckgo", ...}}. - Code interpreter: включён из коробки (Pyodide, в браузере).
GET/POST /api/v1/configs/code_execution. - База знаний (RAG): коллекция
7f60313d-add9-4f99-ad53-89e792295129«DTTB Knowledge Base», embedding локальный (MiniLM). 193 файла.- Синк:
/opt/owui-kb-sync/sync.py(инкрементальный по md5) +run.sh(flock +git pull+ sync), cron*/20на LXC 142. Vault клонирован из Gitea (http://oleg:***@10.0.0.189:3000/oleg/knowledge-base.git). - Синкаются только
projects/decisions/claude-memory/snippets(~200), минус credential-файлы (vault на 1435 .md, 1152 =notes/шум). Пустые и дубль-контент (Open WebUI дедупит по хешу →DUPLICATE_CONTENT/EMPTY_CONTENT400) скрипт ловит и помечает skip в манифесте, чтоб не ретраить.
- Синк:
- Модель
oleg-assistant«Ассистент Олега» = basecc/claude-opus-4-8+ привязанная коллекция (meta.knowledge). Выбираешь её → RAG включается сам, ответы с цитатами. Проверено end-to-end. (Дефолт остался plaincc/claude-opus-4-8для общих вопросов; KB-модель — по выбору.)
Команды
# контейнер
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 ...>'