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

ServicePort(s)Role
gateway3100 / 3200 / 3201MCP endpoint + HTTP/WS API + agent runtime
dashboard3210Operator console (login-walled)
mongo27200 (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:

  1. Verifies Docker + Compose are present and the daemon is reachable.
  2. Copies .env.example → .env and generates strong secrets

(JWT_SECRET, GATEWAY_LOCAL_TOKEN, MONGO_ROOT_PASSWORD), written chmod 600.

  1. Builds the gateway and dashboard images.
  2. Brings the stack up and waits for every healthcheck to pass.
  3. 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 for LLM_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.0 serves 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:

VariableDefaultNotes
COMPOSE_PROJECT_NAMEmyaiContainer-name prefix + volume name
HOST_BIND0.0.0.0127.0.0.1 locks to this host
DASHBOARD_PORT3210Operator console
REQUIRE_LOGINtrueLogin-wall for non-loopback requests
TENANT_ENFORCEtrueMulti-tenancy enforcement
MONGODB_URIbundled mongoPoint at external Mongo/Atlas to opt out
LLM_MODEapiapi (Anthropic key) / bridge / direct
LICENSE_KEY(unset)Optional — activates enterprise mode, offline-verified
AIR_GAPPEDfalsetrue = zero outbound calls beyond your LLM provider
*_MEM_LIMIT1g / 512m / 512mPer-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.