Skip to content

Docker Compose

Production stack: docker/compose.prod.yml — Postgres, Redis, API, CRDT merge worker, queue worker, UI. Marketing (www) and scheduler are optional (Compose profiles).

Services bind to 127.0.0.1 by default so an upstream reverse proxy can terminate TLS.

  1. Copy docker/stack.env.example to docker/stack.env. Set POSTGRES_PASSWORD, APP_KEY, and public URLs (APP_URL, FRONTEND_URL, SESSION_DOMAIN, SANCTUM_STATEFUL_DOMAINS, CORS_ALLOWED_ORIGINS).
  2. Set NOTE_CRDT_MERGE_URL=http://crdt-merge:3000 (default in stack.env.example) so the API calls the internal merge worker instead of Node subprocesses.
  3. Optionally copy api/.env.production.example for reference — production Compose injects env from docker/stack.env via env_file on API services.

From the repository root:

Terminal window
# Local build (testing)
docker build -f docker/api/Dockerfile -t garrison-api:local .
docker build -f docker/ui/Dockerfile \
--build-arg VITE_API_URL=https://api.garrison.test \
--build-arg VITE_WWW_URL=https://www.garrison.test \
-t garrison-ui:local .
# Optional marketing site:
docker build -f docker/www/Dockerfile -t garrison-www:local .
# Or pull from registry after CI
docker pull registry.example.com/group/garrison/api:latest

Set GARRISON_IMAGE_API and GARRISON_IMAGE_UI in .env.production when using a registry. Set GARRISON_IMAGE_WWW only if you enable the www profile.

Terminal window
docker compose -f docker/compose.prod.yml --env-file docker/stack.env up -d postgres redis migrate crdt-merge api queue ui

The migrate service runs php artisan migrate --force once, then exits. Do not run db:seed in production.

After deploy, run the Production smoke checklist (/up, GraphQL auth, CRDT note push).

Enable the www service when you want the Astro marketing site in this stack:

Terminal window
docker compose -f docker/compose.prod.yml --profile www --env-file .env.production up -d

Omit --profile www to run only the API, UI, Postgres, Redis, and queue worker.

Point your proxy at the published localhost ports (defaults):

HostPort
api.garrison.test8080
app.garrison.test8081
www.garrison.test8082 (only with --profile www)

Override with GARRISON_API_PORT, GARRISON_UI_PORT, and GARRISON_WWW_PORT in .env.production.

Terminal window
docker compose -f docker/compose.prod.yml --env-file .env.production pull
docker compose -f docker/compose.prod.yml --env-file .env.production up -d
docker compose -f docker/compose.prod.yml run --rm api php artisan migrate --force
Terminal window
docker compose -f docker/compose.prod.yml --profile scheduler --env-file .env.production up -d

Back up the garrison-postgres Docker volume regularly. Test restore on a non-production host before relying on it.