Ensemble Docs
Self-Hosting

Architecture

Components, dependencies, data flows, and the security model of a self-hosted Ensemble deployment.

This page describes what runs where, what each component depends on, and how the pieces communicate. Read it before you deploy so the configuration and Terraform references make sense in context.

Components

The platform is four container images deployed by the Helm chart. Three are long-running workloads; one is a one-shot job that runs during install and upgrade.

ComponentImageKindPortHealth checkPurpose
webworkflows/webDeployment3000GET /The browser-facing web application and user interface
serverworkflows/serverDeployment3001GET /healthREST API: agent invocation, tools, auth, storage, orchestration
workerworkflows/workerDeployment8080GET /Temporal worker that executes workflow activities
migrationworkflows/migrationJob (hook)n/an/aCreates and migrates the database schema

All images share a single tag that tracks the chart's appVersion, so a given chart version deploys a matching, consistent set of images. See Helm chart for how tags and chart versions relate.

The workloads run as non-root (UID 1000) with a read-only root filesystem and all Linux capabilities dropped. This is why they mount small emptyDir volumes at /tmp and /home/node/.npm.

Dependencies

The chart deploys the application; you provide the services it depends on. Some are created for you by Terraform (in your account); others are external services you bring.

DependencyRequiredProvided byNotes
PostgreSQL 16+YesYouAmazon RDS, Cloud SQL, or Neon. Passed as PG_BASE_URL.
TemporalYesYouTemporal Cloud or a self-hosted Temporal server. Passed as TEMPORAL_*.
Object storageYesTerraformThree buckets: user files, documents, tenant migrations.
Secrets storeYesTerraformAWS Secrets Manager or GCP Secret Manager, synced into the cluster.
KMS keysYesTerraformEnvelope encryption for secrets, connections, and environment data.
Auth providerYesTerraformAWS Cognito or Firebase (Identity Platform).
LLM providersYesYouAt least one of OpenAI, Anthropic, Google, AWS Bedrock, or Vertex AI.
SchedulerOptionalTerraformEventBridge Scheduler (AWS) or Cloud Scheduler (GCP) for timed jobs.
RedisOptionalYouElastiCache or Memorystore. Enables cross-instance caching and AI rate limiting.

Neither Terraform stack creates the Kubernetes cluster, the database, or the Temporal server. Those are prerequisites you stand up first. The Terraform provisions only the supporting cloud resources (storage, secrets, KMS, IAM, auth). See Prerequisites.

Request and data flow

  1. A user or API client hits the ingress (an ALB on AWS or a GCE load balancer on GCP), which terminates TLS and routes by path: /api and other API prefixes go to server, everything else goes to web.
  2. web renders the UI and calls server for data.
  3. server authenticates the request (Cognito or Firebase), reads and writes the PostgreSQL database, stores files in object storage, decrypts secrets and connection credentials with KMS, and calls the configured LLM providers.
  4. For workflow and long-running activities, server schedules work on Temporal; the worker picks up tasks, runs activities (which may call tools, storage, and LLMs), and reports results back through Temporal.
  5. The migration job runs before the app starts (on every install and upgrade) to bring the database schema up to date.

Identity and access

Workloads authenticate to cloud APIs without static credentials:

  • AWS: IRSA (IAM Roles for Service Accounts). The Kubernetes service account workflows-sa is annotated with an IAM role ARN; pods assume that role via the cluster's OIDC provider. The role grants scoped access to the three S3 buckets, the KMS key, Secrets Manager, the scheduler, Cognito admin actions, and Bedrock.
  • GCP: Workload Identity. The Kubernetes service account is bound to a Google service account via the iam.gke.io/gcp-service-account annotation. That service account is granted scoped access to the buckets, KMS keys, Secret Manager, and Vertex AI.

Secrets never live in the chart or in Git. They are stored in your cloud secrets manager and synchronized into the cluster (typically by the External Secrets Operator), then mounted into pods as environment variables. See Configuration.

Multi-tenancy

The platform is multi-tenanted. A single deployment serves many tenants, isolated at the data layer. When self-hosting a single-organization deployment, set SELF_HOSTING=true, which restricts tenant lifecycle operations to a superuser and hides tenant/user switching in the UI.

  • Run worker and (optionally) server nodes in private subnets with a NAT gateway for a stable outbound IP, which you can allowlist with external services such as your database or Temporal.
  • Expose only the ingress publicly. The server, web, and worker services are ClusterIP and are not directly reachable from the internet.
  • Restrict database access to the cluster's security group or VPC.

On this page