eparch
GitHubGet started

Getting Started (Self-Host)

This guide brings Eparch up on a single host with Docker Compose, verifies it is healthy, applies migrations, and opens the UI. For the per-variable reference, see configuration.md.

Eparch’s runtime dependencies are PostgreSQL + pgvector, Redis, MinIO/S3, and OPA — all included in the compose files. There is no Kafka, Milvus, or Vault.

Just want to try it? (one command)

If you only need Docker + openssl, skip the manual setup below:

make quickstart      # or: scripts/quickstart.sh

This generates secrets, starts the two-container monolith in local-auth + mock-model mode (no WorkOS, no model server needed), and prints the URL (http://localhost:8031/). Register the first account to become admin. scripts/quickstart.sh down stops it; reset wipes data + secrets. The rest of this guide covers a real deployment (your own secrets, model, and IdP).


1. Prerequisites

Tool Version Notes
Docker Engine 24+
Docker Compose v2 (docker compose) The v2 plugin, not the legacy docker-compose binary
openssl any To generate the JWT signing key and secret key

For local development (make dev-local)

Tool Version Notes
Go 1.25+
pnpm 9+ Builds/serves the platform UI
Docker + Compose as above Runs the infra stack
buf latest Only needed to regenerate protobuf stubs (make proto-gen)
air latest Hot-reload; auto-installed into ./bin on first make dev-local

make dev-deps installs the Go tooling (buf, air, migrate, golangci-lint, sqlc) into ./bin.


2. Choose a deployment topology

File Containers When to use
deploy/docker-compose.prod.yml 10 app containers + Postgres/Redis/MinIO/OPA/migrate You want to scale or restart services independently
deploy/docker-compose.monolith.yml 2 app containers (eparch + identity) + backends Solo operator / minimal operational surface

Both run the same platform and the same one-shot migrate job. In the monolith, the nine data-plane services run in a single eparch process (selected via EPARCH_SERVICES), while identity stays in its own container on purpose: it connects to Postgres privileged to bypass RLS during cross-tenant login, so it cannot share the monolith’s single POSTGRES_URL. That security boundary is the deployment boundary.


3. Configure secrets

cp deploy/.env.example deploy/.env

Fill in deploy/.env (never commit it — it is gitignored):

Var How to produce it
POSTGRES_PASSWORD Superuser password (used by migrations and identity)
EPARCH_APP_PASSWORD Runtime eparch_app role password (must match infra/compose/postgres-init/02-roles.sql, or edit that file)
EPARCH_SECRET_KEY openssl rand -base64 32 — the AES-256 key for the tool-registry secret store
JWT_RSA_PRIVATE_KEY openssl genrsa 2048 — PEM RSA key the identity service signs platform JWTs with
RUNTIME_SVC_TOKEN Static service-account JWT for internal service-to-service calls
MINIO_ACCESS_KEY / MINIO_SECRET_KEY Object-store credentials (defaults: minioadmin)
WORKOS_API_KEY / WORKOS_CLIENT_ID / WORKOS_REDIRECT_URI WorkOS AuthKit credentials from the WorkOS dashboard

Model backend. Point the gateway at an OpenAI-compatible endpoint with LLM_GATEWAY_URL (chat) and LLM_EMBEDDING_URL (embeddings). LLM_EMBEDDING_URL is required when ENV != local so RAG never silently returns stub vectors. Upstream auth is optional — a self-hosted vLLM/Ollama on a trusted network needs none. For a keyed endpoint (DigitalOcean/OpenAI) set LLM_API_KEY, or point LLM_CONFIG at a models.yaml for multiple providers. See model-providers.md for the full contract.

Generate the two keys quickly:

openssl rand -base64 32                      # → paste into EPARCH_SECRET_KEY
openssl genrsa 2048 | awk 'BEGIN{ORS="\\n"}1' # → paste into JWT_RSA_PRIVATE_KEY

4. Bring the stack up

# Ten-container topology:
docker compose -f deploy/docker-compose.prod.yml --env-file deploy/.env up -d --build

# ...or the monolith:
docker compose -f deploy/docker-compose.monolith.yml --env-file deploy/.env up -d --build

Startup order is handled for you: Postgres becomes healthy → the migrate container runs every service’s migrations as the superuser and exits → the app services start (they depend_on the migrate job completing successfully).


5. What “healthy” looks like

docker compose -f deploy/docker-compose.prod.yml ps
  • postgres, redis, minio report healthy.
  • migrate shows Exited (0) — it is a one-shot job and exiting cleanly is correct.
  • opa and all app services are running.

Check the gateway’s HTTP liveness/readiness probes (served on the gateway HTTP port, 8031):

curl -f http://localhost:8031/healthz    # liveness
curl -f http://localhost:8031/readyz     # readiness

Both return 200 OK and require no auth. The identity service’s JWKS endpoint should also serve keys:

curl -s http://localhost:8011/.well-known/jwks.json

Publishing the gateway API. The gateway’s public REST/chat/SSE API and the health probes listen on the HTTP port 8031; gRPC is 8030. The compose files publish 8030 by default — adjust the gateway ports: mapping to expose 8031 if you serve the REST API to external clients.


6. Run / re-run migrations

The migrate container runs migrations automatically on every up, and it is idempotent — each service records its own version in <svc>_schema_migrations, so re-running is safe. To run migrations manually against a running Postgres:

docker compose -f deploy/docker-compose.prod.yml run --rm migrate

For local (non-container) development, the Makefile target applies every service’s migrations against the local dev database:

make migrate-up      # uses POSTGRES_URL or the eparch_dev default

See operations.md for up/down details.


7. Reach the UI

  • Container self-host: the platform UI is served by the platform-ui build; reach the platform through the gateway. In local development the Vite dev server runs on http://localhost:5173 and proxies /api/* to the gateway (:8031) and /auth/* to identity (:8011).
  • Local dev (make dev-local): open http://localhost:5173.

Port map

Application services (container-internal defaults)

Service gRPC HTTP Notes
gateway 8030 8031 HTTP serves public REST, chat/SSE, /healthz, /readyz, /metrics
identity 8010 8011 HTTP serves OIDC login + JWKS
agent-runtime 8001
rag 8040
eval 8045
tool-registry 8050
tenant 8055
event-broker 8060
audit 8070
agent-config 8086
platform-ui 5173 Vite dev server (local dev)

The gateway also exposes a Prometheus metrics endpoint on METRICS_PORT (default 9090).

Infrastructure (published to the host in local dev)

Component Port(s) Notes
PostgreSQL + pgvector 5432
Redis 6379
MinIO 9000 (API), 9001 (console)
OPA 8181
OTel Collector 4317 (gRPC), 4318 (HTTP), 8889 (Prometheus) dev observability
Jaeger UI 16686 dev only
Prometheus 9090 dev only
Grafana 3000 dev only
Alertmanager 9093 dev only

The Prometheus/Grafana/Jaeger stack is part of the local infra profile for development. For production, set OTEL_EXPORTER_OTLP_ENDPOINT to a managed OTLP backend instead of self-hosting the observability farm.


Next steps

Edit this page on GitHub →