Install with Docker Compose
The trial bundle is a production-shaped Docker Compose stack: the same images (ghcr.io/brutor-ai/*), same topology and same configuration surface you’d run self-hosted, sized for a single machine. This page is the full reference; for the fast path see the quickstart.
What’s in the stack
Section titled “What’s in the stack”| Service | Container | Host port(s) | Purpose |
|---|---|---|---|
| Core Proxy (Rust) | brutor-gateway-core |
8100 | Runtime proxy for LLM/MCP/A2A/OAuth/Skills + Portal API |
| Control Plane (Python) | brutor-gateway-control |
5050 | Admin API, Alembic migrations, tenant seeding |
| Admin Console | brutor-gateway-admin |
3002 | Management UI |
| User Portal | brutor-gateway-portal |
3001 | End-user chat UI |
| KB Uploader | brutor-kb-uploader |
— (internal :8200) | Document extraction, chunking, embedding into Qdrant |
| KB Connector Sync | brutor-kb-connector-sync |
— (internal :8201) | Confluence/Notion/GDrive/Slack/GitHub/Jira/SharePoint sync |
| Skill Runner | brutor-skill-runner |
— (internal :8210) | Sandboxed skill execution — JWT-authed, read-only rootfs, all capabilities dropped |
| mcp-app-map | brutor-mcp-app-map |
— (internal :3001) | Demo MCP server (Leaflet map with MCP-Apps UI) |
| PostgreSQL 16 | brutor-postgres |
5432 | Shared database for both planes |
| Redis 7.4 | brutor-redis |
6379 | Cache, rate-limit counters |
| Qdrant 1.18 | brutor-qdrant |
6333 (REST) / 6334 (gRPC) | Vectors — semantic cache + knowledge bases |
| MinIO | brutor-minio |
9000 (S3 API) / 9001 (console) | S3-compatible media storage |
All image tags follow one variable: BRUTOR_VERSION in .env (e.g. 0.9.68). See upgrades.
Optional services (compose profiles)
Section titled “Optional services (compose profiles)”Profiles add capability without bloating the default stack:
| Profile | Services (host port) | What it adds |
|---|---|---|
local-embedding |
Ollama (11434) | Local embeddings with nomic-embed-text — a fully offline embedding path instead of OpenAI. The Ollama image is ~4 GB plus a ~274 MB first-run model pull. |
kms |
LocalStack (4566), Vault (8200) | Emulated AWS KMS and a real Vault Transit engine for testing the KEY_PROVIDER=aws_kms / vault envelope-encryption modes locally. |
presidio |
Presidio analyzer (3030) | Microsoft Presidio NER engine as an external PII provider for guardrails — stronger entity detection than the built-in patterns. |
anthropic-mock |
Anthropic Enterprise mock (8085) | A mock of the Anthropic Enterprise Analytics API, used to demo Traffic Data Import without an Enterprise plan. |
docker compose --profile local-embedding up -ddocker compose --profile kms --profile presidio up -d # profiles combineThe .env file
Section titled “The .env file”The bundle ships with a working .env — your license key and a unique set of secrets are minted per download. The variables you must understand before going beyond a laptop:
# Required — the core proxy refuses to start without itBRUTOR_LICENSE_KEY=BRUTOR-V1-...
# Image tag for all servicesBRUTOR_VERSION=0.9.68
# Shared secrets — MUST be identical for core + control planeJWT_SECRET=... # openssl rand -hex 32ENCRYPTION_KEY=... # Fernet key, see below
# Per-subsystem secretsQDRANT_JWT_SIGNING_SECRET=... # openssl rand -hex 32SKILL_RUNNER_JWT_SECRET=... # openssl rand -hex 32 — must match between core and skill-runnerPROXY_HEALTH_CHECK_API_KEY=sk_brutor_api_... # 43 url-safe chars after the prefix
# Seeded admin credentials — CHANGE THESESYSTEM_ADMIN_PASSWORD=Admin123!DEFAULT_TENANT_ADMIN_PASSWORD=Admin123!
# MinIO credentials (media storage)MEDIA_S3_ACCESS_KEY_ID=minioadminMEDIA_S3_SECRET_ACCESS_KEY=minioadminGeneration commands for fresh secrets:
openssl rand -hex 32 # JWT_SECRET, QDRANT_JWT_SIGNING_SECRET, SKILL_RUNNER_JWT_SECRETpython3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" # ENCRYPTION_KEYJWT_SECRET and ENCRYPTION_KEY must always match between the core proxy and the control plane — the portal JWT is minted by the proxy and encrypted secrets are written by the control plane and read by the proxy. The full variable reference (ports, database, Redis, semantic cache, KB, media, skills, KMS, CORS, logging) is on the configuration page.
Start, stop, clean up
Section titled “Start, stop, clean up”cd trial_bundle
./docker-start.sh # interactive: checks Docker + license, asks about local embeddingsdocker compose up -d # non-interactive (remote/OpenAI embeddings)docker compose --profile local-embedding up -d
docker compose logs -f gateway-core # follow a service's logsdocker compose down # stop, KEEP data volumes./docker-cleanup.sh # full teardown INCLUDING volumescd trial_bundle
.\docker-start.ps1 # interactive (PowerShell)docker compose up -d # non-interactive
docker compose down # stop, KEEP data volumes.\docker-cleanup.ps1 # full teardown INCLUDING volumesPlain cmd.exe equivalents docker-start.bat / docker-cleanup.bat are also included.
First boot takes a few minutes: the control plane runs its Alembic migrations, seeds the default tenant (admin user, a default group, enabled models, the demo MCP server) and only then reports healthy.
Verify health
Section titled “Verify health”Health endpoints are public by design — Docker’s health checks depend on them, so never put auth in front of them.
curl http://localhost:8100/health # core proxy{ "status": "healthy", "service": "brutor-gateway-core", "components": { "database": "up", "redis": "up" }, "stats": { "active_mcp_sessions": 0, "background_writes": { "scheduled": 12, "completed": 12, "failed": 0, "dropped": 0 } }}The control plane answers on http://localhost:5050/health, and docker compose ps shows the per-container health-check state for everything else.
First login
Section titled “First login”| Surface | URL | Credentials |
|---|---|---|
| Admin Console | http://localhost:3002 | admin / Admin123! (tenant default) |
| User Portal | http://localhost:3001 | trial / Trial123! |
| MinIO console | http://localhost:9001 | minioadmin / minioadmin |
There is also a seeded system admin (sysadmin / Admin123!) for cross-tenant administration. Change all of these before the gateway is reachable by anyone else — via SYSTEM_ADMIN_PASSWORD / DEFAULT_TENANT_ADMIN_PASSWORD in .env before first boot, or in the Admin Console afterwards.
After logging in, paste your provider API key (e.g. OpenAI) into the seeded models under AI Models — the models are enabled but can’t reach a provider until they have a key.
