Self-Host Quickstart
Run the open core of Bike4Mind on your own hardware - a laptop, a server, or your own cloud - with no AWS account or hyperscaler required. The app plus its dependencies (MongoDB, object storage, queues, and a local mail catcher) run as containers via Docker Compose.
The standard path, at a glance (each step is a section below):
- Clone the repo and copy the env template.
- Generate the three security secrets and set your LLM provider key(s).
docker compose -f compose.selfhost.yaml --env-file .env.selfhost up -d- Sign in at
http://localhost:3000with a one-time code read from Mailpit athttp://localhost:8025. The first account becomes the admin. - Create an API key in the app and make your first API call with
curl.
Prefer to run on AWS instead? See the Deployment Guide for the full SST-based cloud path. Want to hack on the code? That's a separate flow - see the Development Setup and the repo's Contributing Guide; this page is about running Bike4Mind.
Prerequisites
- Docker and Docker Compose (Docker Desktop, or Docker Engine + the compose plugin).
- ~4 GB free RAM for the stack (more if you build the image yourself, see below).
- API keys for whichever LLM providers you want to use (Anthropic, OpenAI, Google Gemini, xAI, or a local Ollama endpoint).
You do not need Node, pnpm, or a local build - the app ships as a prebuilt image at ghcr.io/bike4mind/bike4mind-selfhost (multi-arch: amd64 + arm64), published by CI from main.
1. Get the compose files
Clone the repo (or copy compose.selfhost.yaml, elasticmq.conf, and .env.selfhost.example from it):
git clone https://github.com/bike4mind/bike4mind.git
cd bike4mind
2. Configure your environment
Copy the template and fill it in:
cp .env.selfhost.example .env.selfhost
Generate the three security secrets (each a fresh 32-byte hex string):
openssl rand -hex 32 # -> JWT_SECRET
openssl rand -hex 32 # -> SESSION_SECRET
openssl rand -hex 32 # -> SECRET_ENCRYPTION_KEY
Never change SECRET_ENCRYPTION_KEY after first boot. It encrypts other secrets stored in the database - rotating it makes existing encrypted data unreadable.
Compose reads .env.selfhost values verbatim - don't add comments on the same line as a value.
Minimum required to boot: the defaults in the template already point everything (MongoDB, MinIO object storage, ElasticMQ queues, Mailpit mail catcher) at the bundled services - you only need to set the three secrets above.
LLM keys - set the ones you'll use; blank disables that provider. Only models for providers with a key appear in the model picker. You can also add or override keys per-user later, in the app under Settings > API Keys.
ANTHROPIC_API_KEY= # Claude
OPENAI_API_KEY= # GPT
GEMINI_API_KEY= # Google Gemini
XAI_API_KEY= # Grok
# ...plus optional GitHub/Google OAuth, Stripe, Slack - see the template
3. Bring up the stack
docker compose -f compose.selfhost.yaml --env-file .env.selfhost up -d
This pulls the app image and starts it alongside MongoDB, MinIO, ElasticMQ, and Mailpit. When it's healthy, open:
http://localhost:3000
Building from source instead (optional): the prebuilt image is the supported path, but you can build locally with docker compose -f compose.selfhost.yaml --env-file .env.selfhost build. The Next.js monorepo build needs ~12-16 GB of Docker memory (Docker Desktop: Settings > Resources).
4. Sign in
Bike4Mind signs you in with a one-time code sent by email. In the self-host stack, all outgoing mail is caught by the bundled Mailpit - nothing leaves your machine:
- Open
http://localhost:3000, enter your email address, and request a code. - Open Mailpit at
http://localhost:8025and read the code from the sign-in email. - Enter the code and pick a username.
The first account created on a fresh install automatically becomes the admin (no invite code needed). After that, invite-only registration applies - as admin you can issue invites or enable open registration in the admin settings.
For production use, point the MAIL_* variables at a real SMTP provider instead of Mailpit.
5. Make your first API call
Everything you can do in the UI is also available over the HTTP API, authenticated with a scoped API key.
-
Create an API key: in the app, open Settings > API Keys and create a key with the
ai:chatscope. The key (startingb4m_) is shown once - copy it. -
Send a chat message:
curl -X POST http://localhost:3000/api/chat \
-H "x-api-key: $B4M_API_KEY" \
-H "content-type: application/json" \
-d '{"message": "Say hello in five words.", "wait": true}'
wait: true processes the message synchronously and returns the reply in the response; omit it to get a sessionId/questId back immediately and let processing continue in the background. The model defaults to the admin DefaultAPIModel setting; pass "model": "..." to pick any model from /api/models (only providers you configured a key for are available).
The same header works as Authorization: ApiKey <key>. Keys, scopes, and rate limits are managed per-user in Settings > API Keys.
Troubleshooting
- App can't reach Mongo / "no primary" errors - MongoDB must run as a replica set (
--replSet rs0) for transactions; the bundledmongoservice is configured for this. Give it a few seconds to elect a primary on first boot. - No sign-in email arrives - check Mailpit at
http://localhost:8025; if it's empty, checkdocker compose -f compose.selfhost.yaml logs appfor mail errors and verify theMAIL_*values. - A model returns "unauthorized" - that provider's API key is missing or wrong in
.env.selfhost. Only the providers you set keys for are available. - The model picker is empty / "no models" warning - no provider key is configured. Set at least one provider key in
.env.selfhostand restart (docker compose -f compose.selfhost.yaml --env-file .env.selfhost up -d), or add a key in the app under Settings > API Keys. - Chat replies only appear after a refresh - expected for now: the realtime websocket gateway is not part of the compose stack yet, so live streaming updates degrade to fetch-on-refresh.
- Changed
SECRET_ENCRYPTION_KEYand now secrets fail to decrypt - restore the original key; it cannot be rotated in place.
Security notes
The stack is configured for local, single-host use: the backing services (Mongo, MinIO, ElasticMQ, Mailpit) run without authentication and bind to 127.0.0.1 only. Before running on a public-facing server you must enable Mongo auth, change the MinIO credentials, use a real SMTP provider, and put the app behind a reverse proxy with TLS. See the header of compose.selfhost.yaml.
What you get (and don't)
Self-host runs the open-core engine - notebooks, multi-LLM chat, agents, the Quest Master, the knowledge engine, and artifacts. Credit metering is off by default on self-host (the admin can turn it on) - no Stripe, no billing. Bedrock-backed models are hidden on self-host; only providers with a configured key appear.
Known gaps today:
- Realtime streaming - the websocket gateway is not in the stack yet; chat replies and live updates appear on refresh.
- Background enrichment - features that ride the hosted event bus (notebook auto-naming, summaries, tagging) are inert in self-host for now.
- Hosted-service features - billing, entitlements, and premium overlays are not part of the open core; see the open/closed boundary.
Need help? Ask in Discussions.