← all cases · self-hosted AI platform

Self-hosted infrastructure for an open-source AI assistant.

The client, an AI startup in wearables, wanted to move off the upstream Omi project's cloud and run everything on its own VPS: the backend, the database, the LLM and STT keys. Full independence from third-party infrastructure. From the first commit to an APK and an iOS build — 14 days.

timeline · 14 days stack · Python · Firebase · Deepgram in production

01 · Context and task

The client works with Omi, an open-source AI platform (github.com/BasedHardware/omi). It's a voice assistant paired with a wearable device: the microphone records conversations, the backend transcribes them via STT, and an LLM writes summaries and builds the user's Knowledge Graph.

Out of the box, the platform is designed for development via ngrok and the upstream project's cloud services. That means your data flows through someone else's backend, you don't control the keys, and you can't run it on your own servers.

What the client asked for: deploy a fully independent instance of the platform — on their own VPS, with their own Firebase and their own LLM and STT keys. Then ship an Android APK and an iOS build that talk only to this backend. The time budget: 14 days.

02 · What was hard

  • The codebase wasn't built for self-hosting. Out of the box, Omi runs on ngrok plus third-party cloud services. No docker-compose, no deployment guide, no production config. All of that had to be built from scratch on top of someone else's code.
  • Hard dependencies on Pinecone, Redis (Upstash) and Typesense. Omi uses these services at the import and initialization level. Even if the client doesn't need them functionally, the backend simply won't start without them. Each one needed its own decision: a stub, a minimal local instance or a self-hosted alternative.
  • STT and LLM are separate vendors. Deepgram (speech-to-text) and OpenRouter (a proxy to OpenAI) are different APIs with different rate limits and error formats. They had to be wired in so that hitting one provider's limit wouldn't bring down the whole app.
  • Two builds in one contract. Android APK and iOS are different pipelines: Gradle vs Xcode, different signing, different requirements. iOS also required the client's Apple Developer account with provisioning profiles set up.
  • Handover to support. The client is a startup with no DevOps. The documentation had to let a non-developer operator restart a container, update a key or check the logs — without contacting us.

Open-source ≠ a ready-made solution. “Just deploy it” is the first trap in any project like this.

03 · Solutions

Adapting someone else's code without a fork

We didn't fork Omi or modify its source. All self-hosted settings live in .env: API_BASE_URL, Firebase keys, STT/LLM endpoints, stub toggles for Pinecone/Typesense. When the upstream project updates, the client can pull the latest code without losing their settings.

We handled the hard cloud dependencies in the most minimal way possible: Pinecone was replaced with an in-memory stub that has the same interface (the client doesn't need vector search), Redis runs locally in Docker, and Typesense was bypassed — the features that use it are turned off with a flag.

Infrastructure in Docker Compose

The backend, Nginx and Redis are separate services in a single compose file. Compose describes not only how to start them but also the dependencies (Nginx doesn't start until the backend passes its healthcheck) and auto-restart after a VPS reboot (restart: unless-stopped). One file holds the entire infrastructure state.

Onboarding screen: How did you find us
One of the onboarding screens in the built APK, which talks to the self-hosted backend we deployed

SSL via certbot, no manual renewals

Let's Encrypt runs in a separate certbot container. Every 12 hours it checks expiry and issues new certificates on its own. Nginx reloads its config every 6 hours, so fresh certs are picked up with no downtime. The client no longer needs a “renew SSL” reminder in their calendar.

Firebase as “free” storage

Auth (email/password), Firestore (user data) and Storage (audio recordings) all run on the client's own Firebase Blaze plan. We only set up the project, connected a service account to the backend, organized the collections and wrote the security rules. The client didn't have to run a database of their own.

Two STT/LLM providers

Deepgram — STT with the lowest latency for Russian and English. OpenRouter — a proxy to OpenAI and dozens of other LLMs that lets you switch providers via config, with no new releases. The OpenAI key can be swapped for an Anthropic key in a minute — the client stays flexible.

Documentation for a non-developer

The final document isn't a GitHub README.md but a step-by-step operations guide: where each key lives, how to restart, what to do when disk space runs low, how to update the backend URL in the APK. It has 13 sections, all built on simple ssh and docker compose commands.

04 · Result

Timeline 14 daysfrom spec to production build
Platforms 2Android APK + iOS
Integrations 5Firebase · Deepgram · OpenRouter · Nginx · Docker

The client got an instance of the platform on their own VPS (Ubuntu 24.04, 2 vCPU, 4 GB RAM) that is fully independent of the Omi cloud. The backend runs in production, serves the API to the mobile app, talks to Firebase, and spends OpenRouter and Deepgram tokens on the client's own keys.

The Android APK (130 MB, prod flavor) installs on a device the standard way, via installation from unknown sources. The iOS build went to TestFlight for internal testing by the client's team.

Most importantly, it's about control. All user audio recordings and transcripts are now stored in the client's own Firestore, not with third parties. The LLM keys belong to the client. So does the VPS. No lockouts and no pricing surprises from the upstream project.

05 · What's next

The project is under support. The main next steps are expanding functionality (enabling voice onboarding and the Knowledge Graph, which are currently hidden behind a flag), updating for new models on OpenRouter, and publishing to RuStore (Russia's Android app store) and the App Store.

The Omi platform keeps evolving in the upstream repository — we'll pull in updates and adapt them to the client's self-hosted configuration without breaking production.

Similar project

Do you also have an open-source AI project that needs to run on your own infrastructure?

Self-hosting someone else's codebase is a common task for AI startups. In your first message, send a link to the repository and describe what you want to keep in the cloud and what you want to bring in-house. We'll send you a free review and an estimate within 24 hours.