Prerequisites
- Docker and Docker Compose
- A domain name with DNS configured
- Ports 80 and 443 available
| Record | Purpose |
|---|---|
your-domain.com | Control plane web UI |
registry.your-domain.com | Container image registry |
logs.your-domain.com | Log aggregation (Victoria Logs) |
Quick Start
Run the automated install script on a fresh server:Manual Setup
Clone the repository and configure your environment:.env with your values. Set CONTROL_PLANE_UPDATER_TOKEN to
the generated token.
For an external PostgreSQL database, keep:
TECHULUS_CLOUD_VERSION to the release tag you are installing:
tip only for rolling installs. Rolling installs do not show release
update prompts.
Then start the stack:
/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:
Environment Variables
Required
| Variable | Description |
|---|---|
ROOT_DOMAIN | Your domain (e.g., cloud.example.com) |
ACME_EMAIL | Email for Let’s Encrypt certificates |
DATABASE_URL | PostgreSQL connection string (e.g., postgres://user:pass@postgres:5432/techulus) |
BETTER_AUTH_SECRET | Secret key for authentication |
ENCRYPTION_KEY | 32 bytes as a 64-character hex string |
Control plane deployment
| Variable | Description |
|---|---|
COMPOSE_FILE | Compose file used by self-updates. Use compose.production.yml for external PostgreSQL or compose.postgres.yml for bundled PostgreSQL. |
TECHULUS_CLOUD_VERSION | Installed release tag. Use tip only for rolling installs without release prompts. |
CONTROL_PLANE_UPDATER_TOKEN | Random token used by the web app to call the internal updater service. Generate with openssl rand -hex 32. |
Victoria Logs
| Variable | Description |
|---|---|
VL_USERNAME | Logs service username |
VL_PASSWORD | Logs service password |
VL_RETENTION | Log retention period (default: 7d) |
Victoria Metrics
| Variable | Description |
|---|---|
VM_USERNAME | Metrics service username |
VM_PASSWORD | Metrics service password |
VM_RETENTION | Metrics retention period (default: 30d) |
Registry
| Variable | Description |
|---|---|
REGISTRY_USERNAME | Registry username for agents |
REGISTRY_PASSWORD | Registry password for agents |
REGISTRY_HTTP_SECRET | Internal registry secret |
Inngest
| Variable | Description |
|---|---|
INNGEST_SIGNING_KEY | Request verification key (prefix with signkey-prod-) |
INNGEST_EVENT_KEY | Event API key |
Control Plane Replicas
| Variable | Description |
|---|---|
WEB_REPLICAS | Number of control plane web containers to run (default: 1) |
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)
| Variable | Description |
|---|---|
GITHUB_APP_ID | GitHub App ID |
GITHUB_APP_PRIVATE_KEY | GitHub App private key (base64-encoded) |
GITHUB_WEBHOOK_SECRET | Webhook secret |
Generating Secrets
Services
Once running, the following services are available:| Service | Endpoint |
|---|---|
| Web | https://<ROOT_DOMAIN> |
| Registry | https://registry.<ROOT_DOMAIN> |
| Logs | https://logs.<ROOT_DOMAIN> |
| PostgreSQL | Internal only |
| Inngest | Internal only |
Database Migrations
The schema is synced automatically by the one-shotmigrate 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
latest and tip are convenient, but they can
move between pulls.