Docs / Start here
Quick start
Get a single-host Galley running with previews in about ten minutes.
Single host, single agent. Server, message bus, Postgres, ingress proxy, and one colocated agent all run on one machine. Good for evaluation, small teams, and the developer environment of someone who’ll later split things across hosts.
Prerequisites
- Linux host with Docker 24+ and
docker composev2. - Public IP or a tunnel.
- A wildcard DNS record (
*.preview.yourco.dev) pointing at the host. The bare host (preview.yourco.dev) and any sub-subdomains both need to resolve. - 80/443 reachable from the internet (or wherever your reviewers sit).
- Ubuntu 23.10+ / 24.04 LTS only: allow unprivileged user namespaces so rootless BuildKit can boot. See Operations → Ubuntu unprivileged user namespaces.
1. Generate a master key
openssl rand -hex 32
Save the output. This key encrypts every secret in the database (project env vars, webhook secrets, OAuth tokens, the bypass tokens). It never goes into the database, and it’s not recoverable. Lose it and the ciphertext is rubble. Put it in a password manager or a Vault, and back it up somewhere separate from your Postgres backups.
2. Pull the compose file
mkdir -p /opt/galley && cd /opt/galley
curl -fsSL https://galley.sh/install/docker-compose.yml -o docker-compose.yml
The compose file pulls these images and wires them together:
ghcr.io/utibeabasi6/galley-server:1— HTTP APIghcr.io/utibeabasi6/galley-dashboard:1— UI; fronts/api/*for the serverghcr.io/utibeabasi6/galley-agent:1— colocated build / runtime workerpostgres:16-alpine,nats:2.10-alpine,traefik:v3.6
Everything is a published image — no build context.
3. Configure environment
cat > .env <<'EOF'
GALLEY_MASTER_KEY=<hex string from step 1>
POSTGRES_PASSWORD=<openssl rand -hex 16>
GALLEY_PUBLIC_HOST=galley.yourco.dev
GALLEY_PREVIEW_DOMAIN=preview.yourco.dev
GALLEY_LE_EMAIL=ops@yourco.dev
GALLEY_LE_DNS_PROVIDER=cloudflare
CLOUDFLARE_DNS_API_TOKEN=<your DNS provider token>
EOF
chmod 600 .env
Pick the DNS provider that hosts your zone — Galley uses the DNS-01 ACME challenge so wildcards work without exposing any service publicly during issuance. The provider variable names (CLOUDFLARE_DNS_API_TOKEN, ROUTE53_*, etc.) are listed on the DNS and TLS page.
4. Bring up the control plane
docker compose up -d postgres bus galley-server galley-dashboard proxy
docker compose logs -f galley-server
GALLEY_AGENT_TOKEN isn’t set yet, so the agent stays out of this first start. The control plane runs migrations on boot and listens on https://galley.yourco.dev. First startup takes about 30 seconds; you’ll see server listening in the logs when it’s ready.
5. Bootstrap an admin account
The first user becomes an instance admin. Open the public URL and sign up — the first email + password through the form is the owner.
6. Generate an agent token, start the agent
In the dashboard: Admin → Agents → New agent → name it, copy the bootstrap token. Append to .env and bring up the agent:
echo "GALLEY_AGENT_TOKEN=<paste>" >> .env
docker compose up -d galley-agent
The agent registers within a heartbeat (~30s); the Agents table flips to online.
7. Connect GitHub
Admin → Instance → GitHub App: paste the App ID, private key, webhook secret, and client credentials for the App you registered in your org. Once saved, New project lets you install the App on the org and pick a repo. See GitHub setup for the full registration flow.
8. Open a PR
That’s it. Open a pull request against the connected repo. Within a minute you’ll see:
- A new environment in the dashboard, building.
- Live build logs streaming.
- A preview URL when the build finishes.
- A sticky GitHub comment on the PR with the URL and TTL.
Close the PR and the environment tears down within the next few seconds.
Next steps
- Splitting the agent off the control plane host once you outgrow one box: Agents.
- Real DNS + TLS: DNS and TLS.
- Locking previews down: Preview access.
- Backups, upgrades, and adding agents: Operations.