01 · Контекст и задача
Клиент работает с open-source AI-платформой Omi (github.com/BasedHardware/omi) — это голосовой ассистент с подключением к носимому устройству: микрофон записывает разговоры, бэкенд транскрибирует через STT, LLM делает краткое содержание и собирает Knowledge Graph пользователя.
Изначально платформа рассчитана на разработку через ngrok и облачные сервисы основного проекта. Это значит — твои данные идут через чужой бэкенд, ты не контролируешь ключи и не можешь поднять у себя.
Что просил клиент: развернуть полностью собственный экземпляр платформы — на своём VPS, со своим Firebase, со своими ключами к LLM и STT. Чтобы запустить Android APK и iOS-сборку, которые ходят строго к этому бэкенду. Бюджет — 14 дней.




02 · Что было сложно
- Кодовая база не рассчитана на self-hosted. Omi из коробки запускается под ngrok + чужие облачные сервисы. Нет docker-compose, нет инструкции к деплою, нет конфига под прод. Всё это нужно было собрать с нуля поверх чужого кода.
- Жёсткие зависимости от Pinecone, Redis (Upstash), Typesense. Эти сервисы используются в Omi на уровне импортов и инициализации. Даже если функционально клиенту они не нужны — без них бэкенд просто не стартует. Каждый из них — отдельное решение: либо заглушка, либо минимальный локальный инстанс, либо self-hosted альтернатива.
- STT и LLM — отдельные подрядчики. Deepgram (Speech-to-Text) и OpenRouter (прокси к OpenAI) — разные API с разными лимитами и форматами ошибок. Их нужно было подключить так, чтобы при превышении лимита одного из них всё приложение не валилось.
- Две сборки в одном договоре. Android APK и iOS — это разные пайплайны: Gradle vs Xcode, разные подписи, разные требования. iOS дополнительно требовал Apple Developer аккаунт клиента с настройкой провижн-профилей.
- Передача в поддержку. Клиент — стартап, у них нет DevOps. Документация должна быть такой, чтобы оператор-неразработчик мог перезапустить контейнер, обновить ключ, посмотреть логи — без обращения к нам.
Open-source ≠ готовое решение. «Просто разверни» — это первая ловушка любого подобного проекта.
03 · Решения
Адаптация чужого кода без форка
Мы не форкали Omi и не правили исходники. Все настройки self-hosted режима вынесли в .env: API_BASE_URL, ключи Firebase, эндпоинты STT/LLM, переключатели заглушек для Pinecone/Typesense. Когда основной проект обновится — клиент может подтянуть свежий код, не теряя свои настройки.
Жёсткие зависимости от облачных сервисов закрыли минимальными способами: Pinecone заменили на in-memory заглушку с тем же интерфейсом (клиенту векторный поиск не нужен), Redis подняли локальный в Docker, Typesense обошли — функции, которые его используют, отключаются флагом.
Инфраструктура в Docker Compose
Бэкенд, Nginx и Redis — отдельные сервисы в одном compose-файле. Compose описывает не только запуск, но и зависимости (Nginx не стартует, пока backend не отвечает на healthcheck), и автозапуск при ребуте VPS (restart: unless-stopped). Один файл — весь стейт инфры.
SSL через certbot, без ручных продлений
Let's Encrypt подключили через отдельный certbot-контейнер. Он раз в 12 часов проверяет срок действия и сам выпускает новые сертификаты. Nginx раз в 6 часов перезагружает конфиг — чтобы свежие cert'ы подхватились без даунтайма. Клиенту больше не нужно держать в календаре «продлить SSL».
Firebase как «бесплатное» хранилище
Auth (email/пароль), Firestore (пользовательские данные) и Storage (аудиозаписи) — это всё Firebase Blaze клиента. Мы только настроили проект, подключили сервис-аккаунт в бэкенд, разнесли коллекции, написали правила безопасности. Никакой собственной БД клиенту держать не пришлось.
Два STT/LLM-провайдера
Deepgram — STT с самым низким latency для русского и английского. OpenRouter — прокси к OpenAI и десяткам других LLM с возможностью переключения провайдера через конфиг, без релизов. Ключ к OpenAI можно поменять на ключ к Anthropic за минуту — клиент остаётся гибким.
Документация под не-разработчика
Финальный документ — это не README.md для гитхаба, а пошаговая инструкция эксплуатации. Где какие ключи, как перезапустить, что делать если кончается место, как обновить URL бэкенда в APK. Размер — 13 разделов, всё через простые ssh и docker compose команды.


04 · Результат
Клиент получил полностью независимый от облака Omi экземпляр платформы на своём VPS (Ubuntu 24.04, 2 vCPU, 4 GB RAM). Бэкенд работает в проде, отдаёт API мобильному приложению, общается с Firebase, тратит токены OpenRouter и Deepgram по ключам клиента.
Сборка Android APK (130 МБ, flavor prod) ставится на устройство через стандартную установку из неизвестных источников. iOS-сборка ушла в TestFlight для внутреннего тестирования команды клиента.
Самое важное — это контроль. Все аудиозаписи и транскрипты пользователей теперь хранятся в Firestore клиента, не у третьих лиц. Ключи к LLM — у клиента. VPS — у клиента. Никаких блокировок и тарифных сюрпризов от основного проекта.
05 · Что дальше
Проект на поддержке. Основные следующие задачи — расширение функционала (включение голосового онбординга и Knowledge Graph, которые пока скрыты флагом), обновление под новые модели в OpenRouter, и публикация в RuStore / App Store.
Платформа Omi обновляется в основном репозитории — мы будем подтягивать апдейты и адаптировать под self-hosted конфигурацию клиента, без ломки прода.