N Nexus Docs
Deployment

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):

SecretRequired ForDescription
NEXT_PUBLIC_SUPABASE_URLBuildSupabase project URL (baked into web image)
NEXT_PUBLIC_SUPABASE_ANON_KEYBuildSupabase public key (baked into web image)
NEXT_PUBLIC_SENTRY_DSNBuildSentry DSN (optional)
VPS_HOSTVPS DeployServer IP or hostname
VPS_USERVPS DeploySSH user (e.g., deploy)
VPS_SSH_KEYVPS DeploySSH private key
KUBECONFIGK8s DeployBase64-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 rollbacks
  • latest — Always points to the most recent build on main
  • 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:

  1. SSH into the VPS
  2. Sync compose files, Caddyfile, ClickHouse schema, and Grafana dashboards
  3. Update IMAGE_TAG in the remote .env
  4. Pull new images and restart services
  5. Run health checks against the live domain
  6. 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 values

K8s Deploy Workflow

Trigger: Manual dispatch only, with an environment selector (staging or production).

Steps:

  1. Configure kubectl with the KUBECONFIG secret
  2. Select the values file for the target environment
  3. Run helm upgrade --install with the specified image tag
  4. Verify rollout status for all deployments
  5. 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:

  1. Go to Actions > "Deploy to VPS" (or "Deploy to Kubernetes")
  2. Click "Run workflow"
  3. Select the branch and enter the image tag
  4. 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-abc1234

Adding a Staging Environment

  1. Create a staging GitHub environment with its own secrets
  2. Use values-staging.yaml in the K8s deploy workflow
  3. For VPS, create a separate VPS with VPS_HOST_STAGING secret