Verifieddit Deployment

Full verifieddit.com deployment pipeline: Nix OCI build, Skopeo push, Scaleway CR, Pulumi deploy, Cloudflare cache purge

Overview

Verifieddit (verifieddit.com) is a privacy-first media verification platform using C2PA Content Credentials. The frontend is a Vite SPA served by nginx. Deployment follows the Sovereign Architecture SOP: Nix build, Skopeo push, Pulumi deploy.

Repository: Sanmarcsoft/verifieddit-www

Architecture

verifieddit-www/
  flake.nix          -- Nix build (Vite app + Hugo docs + nginx OCI image)
  infra/             -- Pulumi IaC for Scaleway deployment
  services/
    badge-signer/    -- C2PA signing service (Python + c2patool)
    stripe-backend/  -- Stripe billing (Bun/TypeScript)
  workers/
    ddit-shortener/  -- URL shortener Cloudflare Worker
  wrangler.toml      -- Cloudflare Pages config (badges worker)

Full Deployment Pipeline

Step 1: Build the OCI Image

1
2
3
4
cd verifieddit-www

# Build the Vite app + nginx OCI image
nix build .#packages.x86_64-linux.oci-image

This builds:

  1. Stage 1: Vite app (bun install, tsc –noEmit, vite build) as a Fixed-Output Derivation
  2. Stage 2: Hugo docs (if enabled – currently skipped due to PostCSS sandbox issue)
  3. Final: nginx image with static assets

The Clerk publishable key (VITE_CLERK_PUBLISHABLE_KEY) is baked into the Vite bundle at build time. The key is in the flake.nix.

Step 2: Push to Scaleway Container Registry

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Using the convenience script
nix run .#push-image             # pushes as :testing
nix run .#push-image -- prod     # pushes as :production

# Or manually
SCW_SECRET=$(pass sanmarcsoft/scaleway/api-secret)
skopeo copy \
  docker-archive:./result \
  "docker://rg.fr-par.scw.cloud/sanmarcsoft/verifieddit-www:testing" \
  --dest-creds "nologin:${SCW_SECRET}"

Step 3: Deploy via Pulumi

1
2
3
cd infra
nix develop .#infra   # Enter infra shell with pulumi, skopeo, scw
pulumi up --stack testing

Step 4: Verify

1
2
3
4
5
6
# Check container status
scw container container list | grep verifieddit

# Test the endpoint
curl -s -o /dev/null -w "%{http_code}" https://verifieddit.com/
curl -s https://verifieddit.com/ | head -5

Step 5: Purge Cloudflare Cache

After deploying a new version, purge the Cloudflare cache to serve fresh content:

1
2
3
4
5
6
7
8
CF_TOKEN=$(pass cloudflare/api-token)
ZONE_ID=$(pass cloudflare/zones/verifieddit-com)

curl -s -X POST \
  "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \
  -H "Authorization: Bearer ${CF_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything": true}'

Step 6: Promote to Production

After testing:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Retag image
SCW_SECRET=$(pass sanmarcsoft/scaleway/api-secret)
skopeo copy \
  "docker://rg.fr-par.scw.cloud/sanmarcsoft/verifieddit-www:testing" \
  "docker://rg.fr-par.scw.cloud/sanmarcsoft/verifieddit-www:production" \
  --src-creds "nologin:${SCW_SECRET}" \
  --dest-creds "nologin:${SCW_SECRET}"

# Deploy production
cd infra
pulumi up --stack production

Sub-Services Deployment

Badge Signer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
cd services/badge-signer

# Build
nix build .#packages.x86_64-linux.oci-image

# Push
skopeo copy docker-archive:./result \
  "docker://rg.fr-par.scw.cloud/sanmarcsoft/verifieddit-badge-signer:testing" \
  --dest-creds "nologin:$(pass sanmarcsoft/scaleway/api-secret)"

# Deploy
cd infra && pulumi up

Stripe Backend

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
cd services/stripe-backend

# Pre-build (required -- dist/ must exist)
bun install && bun run build

# Build OCI image
nix build .#packages.x86_64-linux.oci-image

# Push
skopeo copy docker-archive:./result \
  "docker://rg.fr-par.scw.cloud/sanmarcsoft/verifieddit-stripe-backend:testing" \
  --dest-creds "nologin:$(pass sanmarcsoft/scaleway/api-secret)"

Badges Worker (Cloudflare)

1
2
3
4
5
6
# Deploy via wrangler
cd verifieddit-www
npx wrangler deploy

# Or for the testing worker
npx wrangler deploy --env testing

FOD Hash Updates

When dependencies change (bun.lock, package.json), the FOD hash in flake.nix must be recomputed:

  1. Edit flake.nix, set outputHash = pkgs.lib.fakeHash;
  2. Run nix build .#packages.x86_64-linux.oci-image 2>&1 | grep "got:"
  3. Copy the printed hash and replace fakeHash with it
  4. Rebuild to verify

Environment Variables

VariableSourceDescription
VITE_CLERK_PUBLISHABLE_KEYBaked in flake.nixClerk frontend key (pk_live_…)
PORTContainer confignginx listen port (default: 8080)
NODE_ENVContainer configAlways “production”

Known Issues

  • Hugo docs build skipped: PostCSS in Nix sandbox is not yet resolved. Docs are currently not included in the OCI image.
  • Clerk key change requires hash recompute: Changing the Clerk publishable key changes the Vite build output, invalidating the FOD hash.