01 · Whole stack
Not just the frontend.
Postgres, Redis, queues, workers — anything you boot in dev
comes up in the preview, on a private network, reachable by
its galley.yml name.
Galley — self-hosted preview environments v1 beta
Open a PR, get a real environment — your services, your Postgres, your Redis. Push a commit, it rebuilds. Close the PR, it's gone.
v1 is in public beta — APIs, schemas, and behavior may shift before 1.0 stabilises. Run it on a host where occasional breakage is fine; production-critical previews aren't quite the right fit yet.
Why this exists
Six PRs share one staging. The reviewer is looking at whichever branch deployed last, and the database state is whatever the last person left it in.
Each PR gets its own subdomain, its own containers, its own database. Webhook closes, environment goes away.
How it's different
01 · Whole stack
Postgres, Redis, queues, workers — anything you boot in dev
comes up in the preview, on a private network, reachable by
its galley.yml name.
02 · Self-hosted
One docker compose up on
a box you own. Source, secrets, and snapshots stay on your
network. No telemetry, no phone-home.
03 · Real config
galley.yml or your existing
docker-compose.yml. Build with your Dockerfile
or fall back to language autodetect — both unprivileged.
The config
galley.yml per repo.
Existing docker-compose.yml?
That works too. TTL, domain, and access live on the project, not
in the repo.
version: 1
services:
web:
kind: web
build:
path: ./web
expose: 3000
depends_on: [api]
env:
API_URL: http://api:3001
api:
kind: api
build:
path: ./api
expose: 3001
depends_on: [postgres, cache]
env:
DATABASE_URL: postgres://app:pw@postgres:5432/app
REDIS_URL: redis://cache:6379
postgres:
kind: database
image: postgres:16
expose: 5432
env:
POSTGRES_USER: app
POSTGRES_PASSWORD: pw
POSTGRES_DB: app
cache:
kind: cache
image: redis:7
expose: 6379 Install
One compose file pulls every control-plane service as a published image. Point a wildcard DNS record at the host and you have previews.
curl -fsSL https://galley.sh/install/docker-compose.yml -o docker-compose.yml
echo "GALLEY_MASTER_KEY=$(openssl rand -hex 32)" > .env
docker compose up -d # On a separate host, after generating a token in
# Admin → Agents → New agent.
sudo docker create --name x galleysh/agent:v1
sudo docker cp x:/usr/local/bin/galley-agent /usr/local/bin/
sudo docker rm x
sudo systemctl enable --now galley-agent Full walk-through with DNS, TLS, and the master key in the quick start docs ↗.