Skip to main content

Deploying with the CI/CD Pipeline

Deploys are branch-driven and automatic: you merge to a branch, and GitHub Actions builds images, ships them, runs migrations, and brings the environment up. There's no manual deploy command in the normal flow.

The branch flow

  • Merge to staging → the staging deploy runs: it builds and pushes staging-latest images and deploys to the staging environment.
  • Merge stagingmain → the production deploy runs: it builds versioned images, deploys to production, and creates a GitHub Release (if the version is new).

CI checks run on the pull request before merge (via the ci-* workflows), not after — so the deploy workflow trusts the already-passed PR checks and doesn't re-run them.

What a deploy does

Each deploy workflow performs the same sequence on the server:

  1. read the version from the VERSION file;
  2. build and push the Docker images to GHCR;
  3. SCP the deploy files to /app/{env}/;
  4. start Postgres and wait for it to be healthy;
  5. run core migrations, then plugin migrations (see Migration Ordering at Deploy Time);
  6. start all services;
  7. start or restart the shared Caddy;
  8. verify API health.

What you set up once

For this to work, the server must be provisioned and four repository secrets configured — DEPLOY_SSH_KEY, DEPLOY_HOST, DEPLOY_USER, and GHCR_TOKEN (a classic PAT with write:packages). If your repo is under a GitHub org, you also need to allow Actions to publish packages (org → Settings → Actions → "Read and write permissions", and package creation enabled). A first-run 403 on docker push almost always traces back to those org package settings or a fine-grained (rather than classic) token.

Verifying a deploy

After a deploy, confirm health on the server with the environment's compose command — ... ps to see services and ... exec api wget -qO- http://localhost:4000/health to check the API (remembering the -p {env} project flag and the VERSION=... prefix; see Day-2 Operations).

The individual GitHub Actions workflows that implement all this are covered file-by-file in The CI/CD GitHub Workflows.