Self-host guide
Run the whole platform — gateway, dashboard, and MongoDB — on your own hardware, in your own network, with your own data. No SaaS dependency, no egress beyond the LLM provider you configure (and none at all pointed at a local model server).
This page is the docs-site summary. The selfhost/ bundle in the repo is the source of truth — its README covers every flag and edge case in full.
What you get
| Service | Port(s) | Role |
|---|---|---|
gateway | 3100 / 3200 / 3201 | MCP endpoint + HTTP/WS API + agent runtime |
dashboard | 3210 | Operator console (login-walled) |
mongo | 27200 (loopback) | State, task queue, RAG corpus — your data |
Everything runs in containers. The only host requirement is Docker Engine 24+ with the Compose v2 plugin — no host Node, no npm.
Running on Kubernetes instead of a single Docker host? Use the bundled Helm chart — same three services, templated for a cluster (Deployments/Services/Ingress, PVC-backed Mongo, configurable values.yaml).
Quick start
git clone https://github.com/knofler/ai_management.git
cd ai_management
./selfhost/install.sh
On first run the installer:
- Verifies Docker + Compose are present and the daemon is reachable.
- Copies
.env.example→.envand generates strong secrets
(JWT_SECRET, GATEWAY_LOCAL_TOKEN, MONGO_ROOT_PASSWORD), written chmod 600.
- Builds the
gatewayanddashboardimages. - Brings the stack up and waits for every healthcheck to pass.
- Prints the console + gateway URLs.
Open the console at http://localhost:3210.
./selfhost/install.sh --no-build # restart after an .env config change
./selfhost/install.sh --status # container + health status
./selfhost/install.sh --down # stop the stack (keeps the data volume)
Before you go to production
Edit selfhost/.env:
ADMIN_EMAIL+ADMIN_PASSWORD— the anti-lockout bootstrap owner, seeded
on every boot, so this login always works.
ANTHROPIC_API_KEY— required forLLM_MODE=api. Leave blank for a
BYO-key / host-CLI bridge, or set OLLAMA_BASE_URL for a local model.
HOST_BIND—0.0.0.0serves the LAN behind your firewall,127.0.0.1
locks everything to this host.
Configuration reference
Full annotated list in selfhost/.env.example; the most common knobs:
| Variable | Default | Notes |
|---|---|---|
COMPOSE_PROJECT_NAME | myai | Container-name prefix + volume name |
HOST_BIND | 0.0.0.0 | 127.0.0.1 locks to this host |
DASHBOARD_PORT | 3210 | Operator console |
REQUIRE_LOGIN | true | Login-wall for non-loopback requests |
TENANT_ENFORCE | true | Multi-tenancy enforcement |
MONGODB_URI | bundled mongo | Point at external Mongo/Atlas to opt out |
LLM_MODE | api | api (Anthropic key) / bridge / direct |
LICENSE_KEY | (unset) | Optional — activates enterprise mode, offline-verified |
AIR_GAPPED | false | true = zero outbound calls beyond your LLM provider |
*_MEM_LIMIT | 1g / 512m / 512m | Per-service RAM caps (~2 GB total default) |
To use your own database instead of the bundled Mongo, set MONGODB_URI in .env; the mongo service still starts but goes unused (comment it out of the compose file if you want it gone entirely).
Data, backup, and security
- Data locality — everything lives in the
${COMPOSE_PROJECT_NAME}-mongo-data
Docker volume on this host. Nothing leaves your network except the LLM API calls you configure. Mongo is bound to loopback by default.
- Backup:
``bash docker run --rm -v myai-mongo-data:/data -v "$PWD":/backup mongo:7 \ tar czf /backup/myai-mongo-$(date +%F).tar.gz -C /data . ``
- Secrets — generated into
.env(chmod 600, gitignored). Rotate by
editing .env and re-running --no-build.
- TLS — terminate at a reverse proxy (nginx/Caddy/Traefik) in front of the
dashboard and gateway HTTP ports; keep HOST_BIND=127.0.0.1 and point the proxy at loopback.
Air-gapped / offline mode
Set AIR_GAPPED=true for a hard guarantee of zero outbound network calls beyond the LLM provider you explicitly configure. Error reporting stays disabled even if a DSN is set, and license verification is unaffected — it was always fully offline (Ed25519 signature check against an embedded public key, no license server, no phone-home). For a fully air-gapped install (no internet at any point, including image build), build the images on a connected machine, transfer them with docker save/docker load, then run with --no-build on the target host.
License activation
The bundle runs fully — everything above — with no license key at all; that's community mode, and it's never a startup blocker. Setting LICENSE_KEY activates enterprise mode. Check status any time:
curl http://localhost:${GATEWAY_HTTP_PORT:-3200}/api/license/status
Next: the Gateway overview for the API surface this stack exposes, or the repo's selfhost/README.md for the complete guide including key-minting and the Helm chart.