CI/CD
Automated Docker builds and deployments using GitHub Actions with ghcr.io image registry.
Overview
NexusCommerce uses GitHub Actions for continuous integration and deployment. The pipeline is split into three workflows: image building, VPS deployment, and Kubernetes deployment. Images are pushed to GitHub Container Registry (ghcr.io).
Key Concepts
Separate Build and Deploy — Image builds happen automatically on every push to main. Deployments are controlled separately — VPS deploys can auto-trigger after a successful build, while Kubernetes deploys are always manual.
GitHub Container Registry — Images are stored at ghcr.io/<owner>/nexuscommerce/<service>. Free, integrated with GitHub, no rate limits for authenticated pulls.
Layer Caching — Docker builds use GitHub Actions cache (type=gha) for layer caching, reducing build times after the first run.
Getting Started
Step 1: Configure GitHub Secrets
Add these secrets to your repository (Settings > Secrets > Actions):
| Secret | Required For | Description |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | Build | Supabase project URL (baked into web image) |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Build | Supabase public key (baked into web image) |
NEXT_PUBLIC_SENTRY_DSN | Build | Sentry DSN (optional) |
VPS_HOST | VPS Deploy | Server IP or hostname |
VPS_USER | VPS Deploy | SSH user (e.g., deploy) |
VPS_SSH_KEY | VPS Deploy | SSH private key |
KUBECONFIG | K8s Deploy | Base64-encoded kubeconfig |
Step 2: Enable workflows
The workflows are at .github/workflows/:
docker-build.yml # Build + push images (auto on push to main)
deploy-vps.yml # Deploy to VPS (auto after build or manual)
deploy-k8s.yml # Deploy to Kubernetes (manual only)Push to main and the build workflow runs automatically.
Step 3: Create a GitHub environment
Create a production environment in your repository settings. This enables deployment protection rules (approval gates, wait timers) for the deploy workflows.
Features
Build Workflow
Trigger: Push to main (when apps/, packages/, services/workers/, or infrastructure/docker/ change), or manual dispatch.
Jobs: Three parallel jobs build API, Web, and Workers images.
Image Tags:
sha-<7-char>— Unique per commit, used for rollbackslatest— Always points to the most recent build onmain- Custom tag via manual dispatch
Build Args: The web image receives NEXT_PUBLIC_* variables as Docker build args from GitHub Secrets. These are inlined at build time by Next.js.
VPS Deploy Workflow
Trigger: Automatically after a successful build workflow, or manual dispatch with a custom image tag.
Steps:
- SSH into the VPS
- Sync compose files, Caddyfile, ClickHouse schema, and Grafana dashboards
- Update
IMAGE_TAGin the remote.env - Pull new images and restart services
- Run health checks against the live domain
- Prune old images
First-time setup: Before the first deploy, SSH into the VPS and create the .env file:
ssh [email protected]
sudo mkdir -p /opt/nexuscommerce
# Copy .env.production.template and fill in valuesK8s Deploy Workflow
Trigger: Manual dispatch only, with an environment selector (staging or production).
Steps:
- Configure kubectl with the
KUBECONFIGsecret - Select the values file for the target environment
- Run
helm upgrade --installwith the specified image tag - Verify rollout status for all deployments
- Print pod, service, and ingress status
CI Workflow (Existing)
The existing ci.yml runs on all pushes and PRs:
- Build and typecheck (pnpm build, pnpm typecheck)
- Lint (pnpm lint)
- Test (pnpm test)
- Python lint (ruff check, ruff format)
Configuration
Manual Deploys
Trigger a deploy from the GitHub Actions UI:
- Go to Actions > "Deploy to VPS" (or "Deploy to Kubernetes")
- Click "Run workflow"
- Select the branch and enter the image tag
- Click "Run workflow"
Rollbacks
Deploy a previous version by specifying its image tag:
# Via GitHub Actions UI:
# Set image_tag to: sha-abc1234
# Or via CLI:
gh workflow run deploy-vps.yml -f image_tag=sha-abc1234Adding a Staging Environment
- Create a
stagingGitHub environment with its own secrets - Use
values-staging.yamlin the K8s deploy workflow - For VPS, create a separate VPS with
VPS_HOST_STAGINGsecret