Skip to main content
You run two long-running services, the control plane and the worker, backed by one Postgres database. Both ship with Dockerfiles you can use as starting points. The application does not depend on a specific cloud provider. Both services need the same DATABASE_URL, CREDENTIAL_ENCRYPTION_KEY, and INTERNAL_INGEST_TOKEN.
You are responsible for TLS termination, network isolation, database backups, secret injection, monitoring, scaling, and rollbacks.

Deploy

1

Build the control plane

The Dockerfile is a generic building block. Adapt the networking, base image, and build arguments to your platform.
2

Serve the app and API from one origin

Serve the built assets in apps/control-plane/dist at your public origin, and route /api/* on the same origin to the control-plane service. Sign-in, OAuth callbacks, and webhooks all depend on one stable origin.
Set BETTER_AUTH_URL to this origin. Set RESPONDER_PUBLIC_URL too if integration callbacks and webhooks should use a different public origin. OAuth redirect URIs and webhook URLs are derived from it.
3

Run the worker

The worker serves no public traffic. It needs outbound access to the database, Daytona, model providers, and connected integrations.
4

Apply migrations

Before each release starts, apply every migration in drizzle/:
5

Turn on automations

Set RESPONDER_NEW_ORGANIZATION_CAPABILITIES=automations,simplified_navigation on the control plane so new workspaces get the automations product. See Self-hosting overview.
Changing the public origin after integrations are connected breaks their OAuth callbacks and webhooks. Update the redirect and webhook URLs in each provider app if you change it.

Required configuration

Generate the encryption key and internal token with:
See Environment variables for every option.

After deployment

Create provider apps for the integrations you want. Each integration page lists the required callback URLs, webhooks, and permissions. Integrations whose provider app is not configured show Unavailable in the app.