Skip to main content

Prerequisites

  • Docker and Docker Compose
  • A domain name with DNS configured
  • Ports 80 and 443 available
You need three DNS records pointing to your server:

Quick Start

Run the automated install script on a fresh server:
The script detects your OS, installs Docker, walks you through DNS and environment configuration, and starts all services.

Manual Setup

Clone the repository and configure your environment:
Edit .env with your values. Set CONTROL_PLANE_UPDATER_TOKEN to the generated token. For an external PostgreSQL database, keep:
Set TECHULUS_CLOUD_VERSION to the release tag you are installing:
Use tip only for rolling installs. Rolling installs do not show release update prompts. Then start the stack:
To use the bundled PostgreSQL instead of an external database:
Production hosts should also cap Docker container logs. The installer creates /etc/docker/daemon.json with json-file rotation on fresh hosts. If Docker is already configured, keep your existing daemon settings and add equivalent log rotation manually.

Manual upgrades

Use the one-click upgrade flow in Settings when possible. If the updater cannot run, update the deployment from the host manually. Back up your .env file and database before upgrading. Then fetch the Compose files for the release, update TECHULUS_CLOUD_VERSION, pull images, and restart the stack:
Rollback after migrations may require restoring the database backup before you restart older images. The Compose files include container health checks for visibility. Plain Docker Compose reports unhealthy containers but does not restart them automatically, so use the common commands below when investigating a self-hosted service.

Environment Variables

Required

AWS KMS BYOK

AWS KMS BYOK is available for AWS-hosted dedicated control planes. The control plane can run in your AWS account or in the Techulus AWS account. Attach an EC2 instance profile or ECS task role to the web service. Do not store static AWS credentials in .env. Set these variables instead of ENCRYPTION_KEY for a new installation:
The role needs kms:GenerateDataKey, kms:Encrypt, kms:Decrypt, and kms:DescribeKey for the configured key. Restrict the cryptographic operations to the role, the exact key, and this encryption context:

Control plane in the Techulus AWS account

You can keep the KMS key and compute agents in your AWS account while running the dedicated control plane in the Techulus AWS account. Grant the Techulus control-plane role direct cross-account access to the KMS key. The application uses that role through the standard AWS credential chain. It does not call AWS STS AssumeRole. Merge statements like these into the KMS key policy in your AWS account. Replace the account IDs and role name. DescribeKey is separate because that operation does not accept an encryption context:
The Techulus control-plane role also needs this identity policy. Set Resource to the full ARN of your KMS key:
Configure ENCRYPTION_KMS_KEY_ARN with the customer-account key ARN and set AWS_REGION to that key’s region. Your compute agents do not need AWS credentials or KMS permissions. They continue receiving the data encryption key during registration. You can revoke future cold-start unwraps by removing the Techulus role from the key policy or disabling the key. This does not erase a key already cached by a running control-plane process or persisted by an existing agent. The first secret operation generates a 32-byte data encryption key. The control plane stores only its KMS-wrapped form in PostgreSQL. Each web process unwraps and caches the key when first needed. The secret ciphertext format and agent behavior remain unchanged. To migrate an existing installation:
  1. Back up PostgreSQL and .env.
  2. Add ENCRYPTION_KMS_KEY_ARN and AWS_REGION. Keep the existing ENCRYPTION_KEY temporarily.
  3. Restart the web service and verify that you can reveal an existing secret and register an agent.
  4. Remove ENCRYPTION_KEY and restart all web replicas.
When a wrapped key already exists, any remaining ENCRYPTION_KEY must contain the same key bytes. The control plane fails closed if they differ. Do not add a newly generated ENCRYPTION_KEY to an existing KMS installation. Do not change ENCRYPTION_KMS_KEY_ARN after initialization. Automatic rotation of the same KMS key is transparent. Moving to another KMS key requires a reviewed rewrap procedure. If KMS is unavailable, cold-started web processes return a service-unavailable response for secret operations and agent registration. Other control-plane features remain available. Warm processes and existing agents can continue using keys already held in memory or local agent configuration. Back up both PostgreSQL and continued access to the KMS key. Deleting the KMS key can make a database restore unrecoverable. Disabling the key blocks future unwraps, but it does not erase keys already cached by running processes or registered agents.

Control plane deployment

Victoria Logs

Victoria Metrics

Registry

Inngest

Control Plane Replicas

When WEB_REPLICAS is greater than 1, Traefik discovers the replicated web containers through Docker and load balances requests for <ROOT_DOMAIN> across them. Schema sync runs once from the dedicated migrate service before the replicated web containers start, so scaling WEB_REPLICAS does not run migrations from every replica.

GitHub Integration (Optional)

Generating Secrets

Services

Once running, the following services are available: Traefik handles TLS termination and automatic certificate renewal via Let’s Encrypt.

Database Migrations

The schema is synced automatically by the one-shot migrate service via drizzle-kit push. Non-destructive changes (adding tables, columns, indexes) are applied automatically. Destructive changes like dropping columns require manual intervention. If schema sync fails, web startup is blocked; inspect the failure with docker compose logs migrate.

Common Commands

Use versioned or digest-pinned image references for production updates when possible. Mutable tags such as latest and tip are convenient, but they can move between pulls.