Skip to content
Beta — Truss is in public beta. Documentation is actively updated but may not reflect the latest changes. Report issues on GitHub.

Self-Hosting

The Quickstart gets a single instance running in one command. This page is the production view: the three ways to run Truss — Docker Compose for a single box, the Helm chart for Kubernetes, and the operator for declarative / fleet management — plus the first-login flow and the hardening you should do before exposing it to the internet.

None of these paths needs a repo clone. All pull the published (cosign-signed) ghcr.io/binarysquadd/truss-* images and bring up the full stack: the API, the dashboard, Postgres, the Ory services (Kratos, Keto, Hydra, Oathkeeper), MinIO, flagd, and Valkey. The current release is v0.3.0.

For a single host. Download the Compose file and an env template, fill in secrets, and start:

Terminal window
curl -fsSLO https://raw.githubusercontent.com/binarysquadd/truss/main/docker-compose.selfhosted.yml
curl -fsSL https://raw.githubusercontent.com/binarysquadd/truss/main/.env.selfhosted.example -o .env.selfhosted
# fill in every GENERATE_* value, e.g. with: openssl rand -hex 32
docker compose -f docker-compose.selfhosted.yml --env-file .env.selfhosted up -d

The dashboard is served at http://localhost:3000. (Prefer one command? The Quickstart installer does the download + secret generation for you.)

The MCP server is an optional add-on, off by default. Turn it on with docker compose -f docker-compose.selfhosted.yml --profile mcp up -d; it listens at http://localhost:8765/mcp.

By default the Compose file uses the published ghcr.io/binarysquadd/truss-* images. To build from source instead, clone the repo and uncomment the build: blocks in the file.

The chart is published (and cosign-signed) as an OCI artifact, so one helm install pulls it directly. No operator, no clone. Secrets you leave unset are auto-generated on first install and reused across upgrades, so a bare install just works:

Terminal window
helm install truss oci://ghcr.io/binarysquadd/charts/truss --version 0.3.0 \
-n truss --create-namespace
kubectl -n truss port-forward svc/truss-dashboard 3000:80 # → http://localhost:3000

Bring your own secrets with --set secrets.encryptionKey=… (or from an external secret manager); any left blank are generated. Images are pinned in the chart and overridable via images.*. For production set publicUrl + corsAllowedOrigins and front it with TLS. Toggle optional components with their flags (e.g. --set mcp.enabled=false), and turn on the bundled 4-signal observability stack (Grafana / Prometheus / Loki / Tempo) with --set observability.backends.enabled=true.

The operator is the declarative, fleet-friendly path: you apply a TrussInstance custom resource and a controller reconciles the app tier to match — healing drift, reporting status conditions, and (optionally) emitting a ServiceMonitor + multi-window burn-rate SLO PrometheusRule for your Prometheus stack. It manages the app tier (API + dashboard) and expects you to bring the backing dependencies (starting with Postgres).

Install the controller + CRD from the release bundle, provide a Postgres connection Secret (a key named database-url), then apply an instance:

Terminal window
kubectl apply -f https://github.com/binarysquadd/truss/releases/download/v0.3.0/install.yaml
kubectl create namespace truss
kubectl -n truss create secret generic truss-db \
--from-literal=database-url='postgres://user:pass@your-postgres:5432/truss'
kubectl apply -f - <<'EOF'
apiVersion: apps.truss.binarysquad.org/v1alpha1
kind: TrussInstance
metadata: { name: truss, namespace: truss }
spec:
version: "0.3.0"
publicURL: https://truss.example.com # required when ingress.enabled
scaling: { profile: small } # small | medium | large
dependencies:
postgres: { mode: byo, existingSecret: truss-db }
observability:
serviceMonitor: true # created only if the Prometheus-operator CRDs exist
prometheusRule: true
otlpEndpoint: http://otel-collector.monitoring:4318 # optional: push traces/metrics/logs
EOF
kubectl -n truss get trussinstance truss -o jsonpath='{.status.phase}' # → Ready

On first boot, with no account yet, Truss seeds a default admin so you can sign in immediately, the same way Grafana and Argo CD do. It only ever runs when the identity store is empty, so it never overwrites real users.

  • Email: [email protected] (override with TRUSS_BOOTSTRAP_ADMIN_EMAIL).

  • Password: set TRUSS_BOOTSTRAP_ADMIN_PASSWORD for a known value, or leave it blank and a random one is printed once to the API logs:

    Terminal window
    docker compose -f docker-compose.selfhosted.yml logs truss-api | grep "Default admin" # Compose
    kubectl -n truss logs deploy/truss-api | grep "Default admin" # Kubernetes

Change it right after logging in under Settings → Account → Change Password. To opt out entirely, set TRUSS_BOOTSTRAP_ADMIN=false and register the first user yourself.

See Configuration for the full list of environment variables.

Hardening (read before exposing to the internet)

Section titled “Hardening (read before exposing to the internet)”
  • CORS_ALLOWED_ORIGINS — set to your dashboard origin(s). CORS fails closed; if unset, the browser app cannot reach the API (intentional).
  • ENCRYPTION_KEY — a random 32+ char string used to encrypt saved connection passwords. If you lose it, those are unrecoverable. The Helm chart and operator auto-generate and persist it (in the truss-secrets Secret); on Compose you set it yourself. Either way, back it up — and note the app refuses to start in production with a placeholder (change-me…) value.
  • COOKIE_SECURE — the session cookie is marked Secure only when you serve over HTTPS. Serving over plain HTTP keeps it off so the cookie is not dropped; set COOKIE_SECURE=true behind an HTTPS-terminating proxy the API cannot detect.
  • TRUSS_ADMIN_IDENTITY_IDS — admin-only features (DB roles, migrations, backups, authz rules) are gated. Grant admin by setting this to your Kratos identity ID(s), comma-separated.
  • Put the API behind TLS, run Postgres with backups (PITR), and never run with dev defaults.

If self-hosting has done its job and you would rather hand off the ops, Truss Cloud is the same platform, hosted and managed, with multi-org, metering, and managed backups. Your client code and API surface stay the same.