Documentation
Self-hosted (Enterprise)
Run the full Context OS stack inside your own infrastructure with one command, under a signed license.
The self-hosted tier runs the whole stack on your own servers. Vault content, the MCP gateway and background jobs never leave your network, and with the optional Ollama service no data goes to an external AI provider either.
Self-hosting is part of Enterprise & Self-Hosted (from $2,000/year). Contact sales for a license key.
What runs
| Service | Purpose |
|---|---|
app | Dashboard, API, MCP gateway (/api/mcp) and browser-extension API (/api/extension/*) |
migrate | One-shot: applies the database migrations (prisma migrate deploy) before app starts |
postgres | PostgreSQL 16 (app database plus a separate inngest database) |
seaweedfs | S3-compatible storage for avatars and storage mirrors |
seaweedfs-init | One-shot: creates the avatars and context-vaults buckets |
inngest | Background jobs: builds, delta sync, allowance renewals, temp cleanup |
ollama | Optional (--profile ollama): fully offline models |
Install
cp .env.enterprise.example .env.enterprise # replace every CHANGE_ME value
docker compose -f docker-compose.enterprise.yml --env-file .env.enterprise up -d
Generate secrets with openssl rand -base64 32 (auth, encryption) and openssl rand -hex 32 (Inngest signing key). Back up CONTEXT_OS_ENCRYPTION_KEY: it protects AI keys, storage credentials and encrypted vault content.
License
The Docker Compose file marks the node as self-hosted (CONTEXT_OS_SELF_HOSTED=true). Put the key you received in CONTEXT_OS_LICENSE_KEY. It is an Ed25519-signed license that names the highest plan the node may run (usually ENTERPRISE_NODE), the licensed seats and the expiry date. CONTEXT_OS_DEFAULT_PLAN picks the plan the node runs as, up to the licensed one. Billing then shows Enterprise · Licensed and no checkout is needed.
Without a valid key the node runs as a regular Free installation.
Offline models with Ollama
docker compose -f docker-compose.enterprise.yml --env-file .env.enterprise --profile ollama up -d
docker compose -f docker-compose.enterprise.yml exec ollama ollama pull llama3.1
Then set CONTEXT_AI_PROVIDER="ollama", CONTEXT_AI_BASE_URL="http://ollama:11434/v1" and CONTEXT_AI_MODEL="llama3.1" in .env.enterprise and run up -d again. Local models do not count against the token allowance. A node-wide OpenAI-compatible server such as vLLM counts as local too: set CONTEXT_AI_PROVIDER="openai-compatible", its URL in CONTEXT_AI_BASE_URL and its model in CONTEXT_AI_MODEL.
Teams and access
Self-hosted vaults use the same folder roles as Team: every folder's allowed roles (Owner, Admin, Member) control what each teammate, and each agent connected through MCP, can read. Expiring, folder-scoped share links give freelancers temporary access.
The first account created on a node becomes its platform admin. After that, people can sign up only with a pending invitation, or with an e-mail address in one of the domains listed in CONTEXT_OS_SIGNUP_DOMAINS (comma-separated, e.g. acme.com). Admins can always create accounts from Admin → Users.
Network and security defaults
- The app and the S3 endpoint listen on
127.0.0.1only. Put a TLS reverse proxy in front of the app (and ofS3_PUBLIC_ENDPOINT). To publish them directly instead, setAPP_BIND_ADDRESS/S3_BIND_ADDRESSto0.0.0.0. - Your proxy must append the client address to
X-Forwarded-For. Per-IP rate limits use the right-most entry; with more than one proxy hop, setCONTEXT_OS_TRUSTED_PROXY_HOPS. - Storage and AI endpoints that people configure in vaults may reach only the private hosts listed in
CONTEXT_OS_PRIVATE_HOST_ALLOWLIST(comma-separated hosts, IPs or CIDRs). The compose file allows the bundledollamaonly; addseaweedfsonly if people mirror vaults to the bundled bucket, and list LAN services such as a vLLM or Gitea host yourself. Cloud metadata and link-local addresses are always refused. Generic git storage accepts local bare repositories only insideCONTEXT_OS_GIT_LOCAL_ROOT. - The app refuses to start while a
CHANGE_MEplaceholder is left in.env.enterprise, or when the auth secret or encryption key is shorter than 32 characters or too repetitive, or when the Inngest signing key is shorter than 64 hex characters. GET /api/healthanswers 503 while the database is unreachable, so your orchestrator can restart or hold traffic.
Notes
PUBLIC_URLis compiled into the app. Rebuild withup -d --buildafter changing it.- Sign-up sends a verification email. Set
RESEND_API_KEY, or pointMAIL_HOST(plus optionalMAIL_PORT,MAIL_USER,MAIL_PASS) at an SMTP relay. With neither, emails, including verification links, are printed to theapplogs. - Stripe billing can stay unset; checkout is then unavailable.
S3_PUBLIC_ENDPOINTmust be reachable from users' browsers, because avatar uploads use presigned URLs.- The interactive API reference (
/api/docs) is off in production. SetCONTEXT_OS_API_DOCS=1to serve it to your integrators.
Still stuck? Contact support and we will help.