Last updated 2026-06-29
Deploy with Docker
This page gets workspaces running in a container — first as a local
Compose stack with Postgres, then as a standalone image in production. The
service ships as a single image,
ghcr.io/elloloop/workspace, built from cmd/workspace.
docker compose up
The repository ships a docker-compose.yml that brings up
Postgres and the workspaces service together. From a clone:
docker compose up -dcurl http://localhost:8080/healthz # -> 200 OKdocker compose logs -f workspacesdocker compose down -v # stop and wipe the postgres volume
Migrations are a deliberate operator step:
GATEWAY_POSTGRES_AUTO_MIGRATE defaults to false,
so apply the schema explicitly with workspace migrate (an init
container or a one-shot job) before serving, or set it to true
for a small dev database to migrate on first connect. See
Configuration for the
full knob reference.
A Compose snippet
A minimal stack: Postgres plus the workspaces service, wired with a durable store, a service-auth token, and a default project.
services: db: image: postgres:16 environment: POSTGRES_USER: workspaces POSTGRES_PASSWORD: password POSTGRES_DB: workspaces healthcheck: test: ["CMD-SHELL", "pg_isready -U workspaces"] interval: 5s retries: 10
workspaces: image: ghcr.io/elloloop/workspace depends_on: db: condition: service_healthy ports: - "8080:8080" # Connect-RPC (HTTP/JSON, gRPC, gRPC-Web) - "9090:9090" # Prometheus metrics + health probes environment: GATEWAY_POSTGRES_DSN: postgres://workspace:password@db:5432/workspace?sslmode=disable GATEWAY_SERVICE_AUTH_TOKENS: prod-token-a,prod-token-b GATEWAY_DEFAULT_PROJECT_ID: my-product
See Configuration for
every GATEWAY_* variable. The three that matter most for a
deployment are above:
-
GATEWAY_POSTGRES_DSN— the durable store. Empty would select the in-memory driver, which is not suitable for production or multiple replicas. -
GATEWAY_SERVICE_AUTH_TOKENS— the accepted service credentials. Callers present one asAuthorization: Bearer <token>. Leaving it empty disables auth and logs a warning. -
GATEWAY_DEFAULT_PROJECT_ID— the project shard for requests that omitproject_id.
Running migrations
Auto-migration is convenient but couples schema changes to process startup.
To run migrations as an explicit, gated step — for example a Compose
one-shot service or a Kubernetes init job — set
GATEWAY_POSTGRES_AUTO_MIGRATE=false and invoke the binary's
migrate subcommand. It applies pending Postgres migrations and
exits:
docker run --rm \ -e GATEWAY_POSTGRES_DSN='postgres://workspace:password@db:5432/workspace?sslmode=disable' \ ghcr.io/elloloop/workspace workspace migratePorts
| Port | Purpose |
|---|---|
8080 | Connect-RPC over HTTP/JSON, gRPC, and gRPC-Web (GATEWAY_CONNECT_PORT). |
9090 | Prometheus /metrics and the /healthz / /readyz probes (GATEWAY_METRICS_PORT). |
Behind a mesh or mTLS
Workspaces is an internal service — never expose port 8080 to the public
internet. Run it on a private network behind your API gateway or product
backend. If a service mesh or mTLS already authenticates every caller at the
transport layer, you may leave GATEWAY_SERVICE_AUTH_TOKENS empty
to skip the redundant bearer check; the service logs a
service_auth_disabled warning so the choice is never silent.
With no mesh, set the tokens. See
Security & Service Auth.
Where to next
- Configuration — every
GATEWAY_*variable. - Health & Metrics — probes, Prometheus, and what to alert on.