Личный AI-чат: от Telegram-бота до полноценного веб-интерфейса
Введение
Когда работаешь с AI-моделями каждый день, хочется иметь удобный интерфейс — с историей диалогов, переключением между моделями и доступом с любого устройства. Не привязанный к конкретному провайдеру, а свой, под полным контролем.
Я прошёл путь от Telegram-бота до полноценного веб-интерфейса на собственном сервере. В этой статье расскажу, какие варианты рассматривал, с какими проблемами столкнулся и почему остановился на Open-WebUI.
Требования
Ключевые критерии выбора:
- Доступ к OpenRouter — единый API для 200+ моделей (Claude, GPT, Gemini, DeepSeek, Qwen). Не хочу привязываться к одному провайдеру.
- Self-hosted — данные остаются на моём сервере, нет подписок и лимитов кроме API.
- Минимум зависимостей — чем меньше контейнеров и баз данных, тем проще эксплуатация.
- Доступ с мобильных — Telegran, PWA или адаптивный веб-интерфейс.
- Простой деплой — Podman Quadlet, rootless, один-два контейнера.
Какие решения рассматривал
NullClaw
Автономный AI-agent runtime на Zig1. Один статический бинарник в 678 КБ, ~1 МБ RAM, старт за 2 мс. Поддерживает 50+ AI-провайдеров (включая OpenRouter, Anthropic, OpenAI, Ollama) и 19 каналов связи: CLI, Telegram, Discord, Signal, Slack, Matrix, WhatsApp, IRC, email. Модульная архитектура на vtable-интерфейсах — провайдеры, каналы, инструменты и memory-движки подключаются как плагины. Встроенный sandbox (Landlock, Firejail) для безопасного выполнения команд.
Плюсы: минимальное потребление ресурсов, работает на $5 ARM-платах, 5300+ тестов, один бинарник без зависимостей.
Минусы: нет собственного веб-интерфейса (нужен NullHub для дашборда), ориентирован на автономных агентов — для простого чата избыточно по концепции и недостаточно по UI.
OpenClaw
Self-hosted AI-ассистент на TypeScript2 с 334K звёздами на GitHub. Gateway-архитектура: центральный WebSocket-шлюз нормализует протоколы 20+ мессенджеров (WhatsApp, Telegram, Slack, Discord, Signal, iMessage, Teams, Matrix) в единый формат и маршрутизирует к AI-агентам. Поддерживает голосовое управление, браузерную автоматизацию, работу с файлами, cron-задачи. Есть веб-UI, нативные приложения для macOS и мобильных, экосистема плагинов через ClawHub.
Плюсы: огромное сообщество, мультиплатформенность (одновременно общаешься через любой мессенджер), actionable AI (не только чат — управление почтой, календарём, автоматизация).
Минусы: требует Node.js 24+, тяжелее по ресурсам. Для задачи “простой веб-чат с OpenRouter” — overkill: Gateway-архитектура с 20+ мессенджерами не нужна, если хочешь только веб-интерфейс.
Nanobot
Telegram-бот с AI через OpenRouter. Удобен тем, что Telegram уже установлен на всех устройствах — нулевой барьер входа.
Плюсы: мгновенный доступ из Telegram, не нужен отдельный интерфейс.
Минусы: Telegram как платформа для AI-чата оказался неудобен по нескольким причинам. Во-первых, один чат — один поток: все разговоры на разные темы сливаются в единую ленту, и найти нужную информацию через неделю практически невозможно. Во-вторых, ограничения Telegram по форматированию — markdown рендерится не полностью, длинные ответы обрезаются, блоки кода отображаются плохо. В-третьих, нет удобного переключения моделей на лету. Наконец, после блокировки Telegram Bot API пришлось настраивать proxy для бота, что добавило ещё один компонент в инфраструктуру — лишний overhead ради неидеального интерфейса.
LibreChat
Мощная мультипровайдерная платформа3: 30+ LLM-провайдеров, AI Agents, MCP, Code Interpreter, OIDC/2FA. React + Node.js.
Плюсы: энтерпрайз-фичи (2FA, модерация, агенты), MCP-интеграция.
Минусы: MongoDB обязательна, MeiliSearch для поиска, Redis для масштабирования — три дополнительные зависимости. Для single-user сильный overkill. Сообщество в 3.7 раза меньше, чем у Open-WebUI (34.9K vs 126.8K звёзд).
Dify
LLMOps-платформа4 с визуальным конструктором workflow. Это не чат-интерфейс, а среда разработки AI-приложений.
Плюсы: drag-and-drop workflow, 50+ встроенных инструментов, мониторинг.
Минусы: 11 контейнеров в деплое (api, worker, web, db, redis, qdrant, sandbox, nginx…), минимум 4 CPU/16 GB RAM для production. Совершенно другая категория — для multi-step AI-пайплайнов, не для простого чата.
LobeChat
Современный AI-чат5 с агентами и маркетплейсом. Next.js, красивый UI, поддержка 13+ провайдеров.
Плюсы: отличный дизайн, система агентов с маркетплейсом, CRDT-синхронизация между устройствами.
Минусы: PostgreSQL 14+ обязателен для серверной версии, плюс Redis — итого 7 GB RAM. Без серверной версии данные хранятся только в IndexedDB браузера. Менее зрелый проект, чем Open-WebUI.
Open-WebUI
Чат-интерфейс6 для Ollama и облачных провайдеров. Python backend, Svelte frontend, SQLite.
Плюсы: один контейнер, SQLite из коробки, 126.8K звёзд на GitHub, PWA, knowledge base, memory, web search, Tools/Functions из маркетплейса.
Минусы: Python backend потребляет ~1-2 GB RAM — больше, чем у Go/Zig-альтернатив.
Почему остановился на Open-WebUI
Выбор определился пересечением требований:
| Критерий | NullClaw | OpenClaw | Nanobot | LibreChat | Dify | LobeChat | Open-WebUI |
|---|---|---|---|---|---|---|---|
| Веб-интерфейс | - | + | - | + | + | + | + |
| OpenRouter | + | + | + | + | + | + | + |
| SQLite / без внешней БД | + | + | + | - | - | - | + |
| 1 контейнер | + | - | + | - | - | - | + |
| История диалогов | - | + | + | + | + | + | + |
| Переключение моделей | + | + | - | + | + | + | + |
| PWA | - | - | - | - | - | + | + |
| OIDC | - | + | - | + | + | + | + |
| Code Interpreter | - | - | - | + | + | - | + |
| Минимум ресурсов | + | - | + | - | - | - | + |
Open-WebUI — единственное решение, которое закрывает все требования при минимальной сложности деплоя. Один контейнер, SQLite, никаких внешних зависимостей.
Деплой в Podman Quadlet свёлся к одному .container файлу и паре переменных окружения. Сервис доступен только через Tailscale — публикации в интернет не нужно.
Установка и настройка
Quadlet-файл контейнера
Open-WebUI запускается одним контейнером через Podman Quadlet. Файл open-webui.container:
[Unit]
Description=Open-WebUI AI chat interface
After=network-online.target
[Container]
ContainerName=open-webui
Image=ghcr.io/open-webui/open-webui:main
Volume=%h/volumes/open-webui:/app/backend/data:Z
EnvironmentFile=%h/.config/containers/systemd/open-webui/open-webui.env
EnvironmentFile=%h/volumes/open-webui/.env
Network=caddy-private.network
AutoUpdate=registry
HealthCmd=curl -fsS http://127.0.0.1:8080/health
HealthInterval=30s
HealthTimeout=5s
HealthRetries=3
[Service]
Restart=always
[Install]
WantedBy=default.target
Ключевые моменты:
- Один volume —
~/volumes/open-webuiхранит SQLite-базу, uploads и кэш. - Два EnvironmentFile — первый с настройками (git-tracked), второй с секретами (только на сервере).
- Network —
caddy-private.networkподключает контейнер к сети приватного Caddy за Tailscale. - AutoUpdate=registry — автоматическое обновление образа через
podman auto-update. - HealthCmd — Podman проверяет
/healthкаждые 30 секунд, рестартует при 3 неудачах.
Переменные окружения
Конфигурация разделена на два файла. Основной open-webui.env (не содержит секретов):
# Провайдеры
ENABLE_OPENAI_API=true
ENABLE_OLLAMA_API=true
OLLAMA_BASE_URL=https://ollama.com
OPENAI_API_BASE_URL=https://openrouter.ai/api/v1
# Регистрация (первый пользователь = admin)
ENABLE_SIGNUP=true
# Веб-поиск
ENABLE_RAG_WEB_SEARCH=true
RAG_WEB_SEARCH_ENGINE=tavily
RAG_WEB_SEARCH_RESULT_COUNT=5
BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL=true
BYPASS_WEB_SEARCH_WEB_LOADER=true
RAG_TOP_K=10
Секреты в отдельном .env файле (не в git):
OPENAI_API_KEY=sk-or-... # OpenRouter API key
WEBUI_SECRET_KEY=... # JWT secret (openssl rand -hex 32)
OLLAMA_API_KEY=... # Ollama Cloud key
RAG_WEB_SEARCH_API_KEY=... # Tavily API key
BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL=true — важная настройка. Без неё Open-WebUI пропускает результаты поиска через embedding-модель и RAG-пайплайн, что требует отдельной embedding-модели. С bypass результаты поиска идут напрямую в контекст LLM — проще и быстрее.
Запуск
# Создать директорию для данных
mkdir -p ~/volumes/open-webui
# Создать файл секретов
cat > ~/volumes/open-webui/.env << 'EOF'
OPENAI_API_KEY=sk-or-ваш-ключ
WEBUI_SECRET_KEY=$(openssl rand -hex 32)
EOF
# Перезагрузить Quadlet и запустить
systemctl --user daemon-reload
systemctl --user start open-webui
После старта Open-WebUI доступен на порту 8080. Первый зарегистрированный пользователь автоматически получает роль admin.
Подключение провайдеров
OpenRouter — основной провайдер
OpenRouter7 предоставляет единый OpenAI-совместимый API для 200+ моделей. Подключение тривиально — переменные окружения:
OPENAI_API_BASE_URL=https://openrouter.ai/api/v1
OPENAI_API_KEY=sk-or-...
После старта контейнера все модели OpenRouter появляются в выпадающем списке. Можно переключаться между Claude, GPT, Gemini, DeepSeek в одном диалоге.
Ollama Cloud — бесплатные большие модели
Отдельно подключил Ollama Cloud8 — облачный сервис от Ollama, который позволяет запускать большие модели (DeepSeek V3.1 671B, Qwen3 235B, MiniMax) без локального GPU.
Бесплатный tier с лимитами по запросам (сброс каждые 5 часов и каждые 7 дней). Достаточно для личного использования — запустить DeepSeek V3.1 на 671B параметров бесплатно трудно переоценить.
Веб-поиск через SearXNG
Open-WebUI поддерживает интеграцию с поисковыми движками. У меня уже был развёрнут SearXNG9 — метапоисковик, агрегирующий результаты из Google, Bing, DuckDuckGo и десятков других источников.
Подключение: Admin → Settings → Web Search → SearXNG → URL.
Теперь модель может искать актуальную информацию в интернете прямо из чата. При этом используется мой собственный SearXNG-инстанс — никакие запросы не уходят в сторонние поисковые API.
Дополнительно подключил Tavily как альтернативный поисковый провайдер — он специализирован на AI-поиске и возвращает более структурированные результаты.
Создание агента
Одна из самых полезных возможностей Open-WebUI — создание кастомных агентов (моделей с предустановленными параметрами).
В разделе Workspace → Models можно создать агента с:
- Фиксированной моделью — например, привязать к DeepSeek V3.2 для повседневных задач или Claude для кода.
- System prompt — инструкции, определяющие поведение: язык ответов, стиль, область экспертизы.
- Навыками (Tools) — подключить Web Search, Run Code, Adaptive Memory.
- Knowledge base — привязать документы для RAG-поиска.
Это упрощает ежедневную работу: вместо того чтобы каждый раз выбирать модель, настраивать контекст и подключать инструменты — просто выбираешь нужного агента из списка. Один для написания кода, другой для исследований с веб-поиском, третий для анализа документов.
Масштабирование: PostgreSQL и Redis
SQLite достаточно для одного пользователя, но Open-WebUI поддерживает расширенную конфигурацию с PostgreSQL и Redis. Это имеет смысл, когда нужно:
- Несколько воркеров — SQLite не поддерживает параллельную запись, при
UVICORN_WORKERS > 1нужна полноценная БД. - Векторный поиск (RAG) — pgvector позволяет хранить embeddings в PostgreSQL вместо встроенного ChromaDB.
- WebSocket-синхронизация — Redis/Valkey как брокер для синхронизации состояния между воркерами.
Дополнительные контейнеры
PostgreSQL с расширением pgvector:
[Container]
ContainerName=open-webui-db
Image=docker.io/pgvector/pgvector:pg17
Volume=%h/volumes/open-webui-db/data:/var/lib/postgresql/data:Z
Volume=%h/.config/containers/systemd/configs/open-webui/init.sql:/docker-entrypoint-initdb.d/init.sql:ro,Z
EnvironmentFile=%h/.config/containers/systemd/open-webui/open-webui-db.env
EnvironmentFile=%h/volumes/open-webui/.env
UserNS=keep-id:uid=999,gid=999
Network=open-webui_db.network
Valkey (Redis-совместимый) для WebSocket:
[Container]
ContainerName=open-webui-redis
Image=docker.io/valkey/valkey:8-alpine
Exec=valkey-server --save 30 1 --loglevel warning
Volume=%h/volumes/open-webui-redis/data:/data:Z
UserNS=keep-id:uid=999,gid=1000
Network=open-webui_db.network
Init-скрипт для PostgreSQL (init.sql) — одна строка:
CREATE EXTENSION IF NOT EXISTS vector;
Изменения в конфигурации Open-WebUI
# Включить 3 воркера
UVICORN_WORKERS=3
# Переключить векторную БД на pgvector
VECTOR_DB=pgvector
# Connection pool
DATABASE_POOL_SIZE=5
DATABASE_POOL_MAX_OVERFLOW=5
# Redis для WebSocket
ENABLE_WEBSOCKET_SUPPORT=true
WEBSOCKET_MANAGER=redis
Строки подключения к PostgreSQL (DATABASE_URL) и Redis (WEBSOCKET_REDIS_URL) передаются через файл секретов.
Изолированная сеть
Контейнеры БД и Redis подключаются к отдельной сети open-webui_db.network, а Open-WebUI входит в обе сети — caddy-private (для HTTP-трафика) и open-webui_db (для доступа к БД). PostgreSQL и Redis не видны ни из какой другой сети.
Стоит ли усложнять?
На практике для single-user конфигурации SQLite хватает с запасом. Я пробовал миграцию на PostgreSQL + Redis + 3 воркера — работает, но прироста производительности при одном пользователе не заметно, а вот три дополнительных контейнера нужно обслуживать. В итоге вернулся на SQLite.
Миграция имеет смысл, если:
- Подключаете нескольких пользователей и хотите параллельную обработку запросов.
- Активно используете Knowledge Base с большими коллекциями документов (pgvector эффективнее ChromaDB).
- Нужна надёжная репликация и бекапы БД (pg_dump vs копирование SQLite-файла).
Выводы
Путь от API-прослойки и Telegram-бота до полноценного веб-интерфейса занял несколько итераций. Главные уроки:
Простота побеждает: один контейнер с SQLite надёжнее кластера из MongoDB + Redis + MeiliSearch. Для single-user нет смысла в энтерпрайз-архитектуре.
OpenRouter решает проблему выбора провайдера: один API key — доступ ко всем моделям. Не нужно жонглировать ключами от OpenAI, Anthropic, Google.
Ollama Cloud — неожиданно полезен: бесплатный доступ к моделям на 671B параметров. Подключается как второй OpenAI-совместимый endpoint.
Кастомные агенты экономят время: настроить модель + system prompt + инструменты один раз, а потом просто выбирать из списка — это реально удобнее, чем каждый раз конфигурировать с нуля.
Self-hosted AI-чат в 2026 году — это один контейнер: не нужен кластер Kubernetes или десяток Docker-контейнеров. Open-WebUI + SQLite + Podman Quadlet — и у вас полноценный AI-интерфейс за VPN.
Источники
OpenClaw — self-hosted AI-ассистент на TypeScript, 334K звёзд ↩︎
Open-WebUI — AI-чат интерфейс, 126.8K звёзд ↩︎
OpenRouter — единый API для 200+ LLM ↩︎
Ollama Cloud — облачные модели ↩︎