You host one thing: the backend (API, dashboard, Postgres) as a single docker compose stack. The connector runs on each user's machine and never needs hosting. Secret values never leave your machine in either mode.
docker-compose.yml:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: gcontext
POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env.selfhost}
POSTGRES_DB: gcontext
volumes:
- gcontext-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gcontext"]
interval: 5s
timeout: 3s
retries: 10
app:
image: ghcr.io/bleak-ai/gcontext-cloud:latest
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://gcontext:${DB_PASSWORD}@db:5432/gcontext
# This chosen token IS your API token. Use it as GCONTEXT_TOKEN
# in your connector config.
GCONTEXT_DEV_TOKEN: ${GCONTEXT_TOKEN:?set GCONTEXT_TOKEN in .env.selfhost}
# Empty = machines-only (no human login). Set a 32+ char string
# to enable dashboard login with your GCONTEXT_TOKEN.
SESSION_SECRET: ${SESSION_SECRET:-}
PUBLIC_ORIGIN: ${PUBLIC_ORIGIN:-http://localhost:8770}
HOST: "0.0.0.0"
PORT: "8770"
ports:
- "${PORT:-8770}:8770"
volumes:
gcontext-db:.env.selfhost:
# --- required --- DB_PASSWORD=change-this-postgres-password # Your API token. The connector uses this as GCONTEXT_TOKEN. # Pick a long random string. GCONTEXT_TOKEN=change-this-to-a-long-random-string # --- optional --- # Enable dashboard login with your GCONTEXT_TOKEN (no OAuth needed). # Leave unset for machines-only mode. # SESSION_SECRET=a-random-string-at-least-32-characters-long # Public URL if not localhost. Default: http://localhost:8770 # PUBLIC_ORIGIN=https://gcontext.example.com
docker compose --env-file .env.selfhost up -d
curl -s http://localhost:8770/health # -> {"ok": true, "version": "..."}Postgres runs alongside, schema migrations apply automatically on every boot, and your GCONTEXT_TOKEN becomes the API token. No OAuth apps needed for single-tenant use. To also sign in to the web dashboard in a browser, set SESSION_SECRET and restart; the login page then asks for your GCONTEXT_TOKEN directly.
In your MCP client config (Claude Code, Claude Desktop, or any MCP client):
{
"mcpServers": {
"gcontext": {
"command": "uvx",
"args": ["gcontext-mcp"],
"env": {
"GCONTEXT_API_URL": "http://localhost:8770",
"GCONTEXT_TOKEN": "the-same-token-you-set-in-.env.selfhost"
}
}
}
}Secret values and script execution stay on your machine, exactly as in the hosted product. Self-hosting only moves the structure and metadata store onto your box.
docker compose --env-file .env.selfhost pull docker compose --env-file .env.selfhost up -d curl -s http://localhost:8770/health # confirm the version bumped
Migrations apply automatically on boot and your Postgres volume is preserved. The API surface is additive-only (functions are never renamed or removed), so an older connector keeps working against a newer backend.
The Docker image is free for your own use (personal or company-internal). Reselling it as a hosted service is not allowed. Stuck? Email us.