Skip to content
Galley

Docs / Install

Control plane

The compose file in detail — services, ports, volumes, environment variables.

The control plane is one Compose project. Five services, all published images, no source build. This page walks through what each piece does and how to configure it.

Compose file shape

The bundled compose file at https://galley.sh/install/docker-compose.yml is the source of truth. The high-level layout:

  • galley-server — the HTTP API, webhook receiver, dashboard, audit log.
  • galley-agent — colocated build/runtime worker for single-host installs. Skip this service when running agents on separate hosts.
  • Postgres — control-plane state.
  • Message bus — build job dispatch + live event streams between server and agents.
  • Ingress proxy — wildcard subdomain routing + TLS termination for previews and the dashboard.

Use the bundled compose file rather than hand-copying. It stays in sync with the latest image tag and the env-var defaults.

Required environment variables

VariableWhat it isExample
GALLEY_MASTER_KEY32 hex bytes (64 chars). Encrypts every secret. Never recoverable.openssl rand -hex 32
GALLEY_PUBLIC_URLThe URL the dashboard lives at.https://galley.yourco.dev
GALLEY_PUBLIC_HOSTSame host without the scheme.galley.yourco.dev
GALLEY_PREVIEW_DOMAINThe wildcard suffix preview URLs land under.preview.yourco.dev
GALLEY_LE_EMAILLet’s Encrypt registration email.ops@yourco.dev
GALLEY_LE_DNS_PROVIDERDNS provider name (used by the ACME DNS-01 challenge).cloudflare
POSTGRES_PASSWORDPostgres password. Anything; the database is internal.openssl rand -hex 16
GALLEY_AGENT_TOKENOne-time bootstrap token the agent uses to register.(see below)

DNS provider variables (e.g. CLOUDFLARE_DNS_API_TOKEN, AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY, GCE_PROJECT + GCE_SERVICE_ACCOUNT_FILE) are picked up by the cert resolver — see the DNS and TLS page for the full provider table.

Generating the agent bootstrap token

Tokens are scoped to the server’s master key. The simplest path:

  1. Bring the server up first with the agent commented out.
  2. Sign in, go to Admin → Agents → New agent, name it (local-host, agent-1, whatever), copy the token.
  3. Set GALLEY_AGENT_TOKEN in .env, uncomment the agent service, and docker compose up -d galley-agent.

The token is hashed in the database (SHA-256) and has an expiry — agents register once, exchange the bootstrap for a long-lived credential, then talk over the message bus only.

Volumes, ports, networking

  • galley-pg is the only stateful volume that must survive across upgrades. Back it up the way you back up any Postgres.
  • galley-bus holds in-flight messages — durable but small (build jobs, deployment events). Lose it and you lose at most an hour of in-flight events.
  • galley-tls stores the Let’s Encrypt account + issued certs. Lose it and re-issuance fires on next boot; you’ll briefly serve self-signed.
  • galley-agent-data is the agent’s worktree cache + per-build export dirs. Disposable; deleting it forces fresh git clones on next deploy.
  • Public ports: 80 redirects to 443, 443 is the only port that needs to be reachable. Postgres, the message bus, and the server’s HTTP port stay on the internal compose network.
  • Docker socket: the proxy reads it for label-based routing; the agent uses it to control containers. The server does not need it.

What the server does and doesn’t expose

The server publishes:

  • The dashboard at GALLEY_PUBLIC_URL.
  • The JSON API under /api/v1/.
  • SSE streams under /api/v1/stream/.
  • The webhook receiver at /api/v1/webhooks/....

That’s it. Everything else stays inside the compose network. If your network policy is “expose 443 and lock the rest”, you don’t need any other rule.

Healthchecks

The server has /healthz and /readyz (no auth required). The proxy probes these by default. If you front Galley with an external load balancer, point its health check at /healthz.