Self-Hosting

Run OpenWorkers on your own infrastructure.


Requirements

  • Docker + Docker Compose
  • TLS certificate and key (the proxy terminates HTTPS)
  • The ow CLI, for migrations and platform administration
  • GitHub OAuth app, for dashboard sign-in

Quick Start

# Clone the infra repo
git clone https://github.com/openworkers/openworkers-infra.git
cd openworkers-infra

# Configure environment
cp .env.example .env
# Edit .env with your values

# Start the database
docker compose -f compose.yml -f compose.dev.yml up -d postgres

# Run migrations over a direct database connection
ow alias set infra --db postgres://openworkers:<password>@localhost:5432/openworkers
ow infra migrate status
ow infra migrate run

# Generate the Postgate token for the platform database (id: the nil UUID)
docker compose up -d postgate
docker compose exec postgate postgate gen-token 
  00000000-0000-0000-0000-000000000000 api 
  --permissions SELECT,INSERT,UPDATE,DELETE
# Copy the token to .env as POSTGATE_TOKEN=pg_xxx...

# Start all services
docker compose up -d

compose.dev.yml publishes port 5432 on the host, which the CLI needs for the migration step.

The REST API and the dashboard are one worker deployed on the platform itself, so the stack is not complete until that worker is uploaded. Claiming the system user, configuring platform storage, and deploying the API worker are covered in GETTING_STARTED.md.


Stack

ServiceDescription
postgresPostgreSQL database
natsMessage queue for logs and scheduled events
postgateHTTP proxy for PostgreSQL
openworkers-runnerWorker runtime (V8 isolates), 3 replicas
openworkers-logsLog ingestion and SSE streaming
openworkers-schedulerCron job scheduler
openworkers-proxyNginx reverse proxy, terminates TLS

The REST API and the dashboard are not services here: openworkers-api is deployed as a worker and served by the runner, like any other worker.


Architecture

                     ┌─────────────────┐
                     │  nginx (proxy)  │
                     └────────┬────────┘
                              │
               ┌──────────────┴──────────────┐
               │                             │
      ┌────────┴────────┐          ┌─────────┴─────────┐
      │  runner (x3) *  │          │      logs *       │
      │                 │          │                   │
      │  every worker,  │          │  SSE log stream   │
      │  API included   │          │                   │
      └────────┬────────┘          └─────────┬─────────┘
               │                             │
               └──────────────┬──────────────┘
                              │
                    ┌─────────┴─────────┐
                    │       nats        │
                    └─────────┬─────────┘
                              │
                    ┌─────────┴─────────┐
                    │    scheduler *    │
                    └───────────────────┘

  * = also reads and writes PostgreSQL, directly or through postgate

Single database: All components share one PostgreSQL database. Postgate uses views that map to OpenWorkers tables.


Configuration

Required Environment Variables

VariableDescription
POSTGRES_USERDatabase user
POSTGRES_PASSWORDDatabase password
POSTGRES_DBDatabase name
DATABASE_URLConnection string for runner, logs and scheduler
NATS_SERVERSNATS URL
POSTGATE_URLPostgate endpoint
POSTGATE_TOKENToken for the platform database (generated above)
POSTGATE_SYSTEM_TOKEN_SECRETSecret used to derive tokens for user databases
GITHUB_CLIENT_IDOAuth app client ID
GITHUB_CLIENT_SECRETOAuth app secret
JWT_ACCESS_SECRETJWT signing key (min 32 chars)
JWT_REFRESH_SECRETJWT refresh key (min 32 chars)
HTTP_TLS_CERTIFICATEPath to TLS certificate
HTTP_TLS_KEYPath to TLS private key

The GitHub, JWT and Postgate secrets are consumed by the API worker. Set them on its environment with ow env set, as described in the infra walkthrough.


Updating

# Pull latest images
docker compose pull

# Restart services
docker compose up -d

# Apply new migrations (if any)
ow infra migrate run

Resources