Skip to content

Deployment topology

Everything runs in the vumbnail.com Cloudflare zone. The product is a small set of Workers plus an edge Snippet; several supporting and legacy Workers sit around them.

WorkerRouteRole
vumbnail-thumbnailvumbnail.com/* (apex catch-all)the product: resolve + watermark + serve thumbnails
(Snippet) watermark-routerruns ahead of the apex Workerhot-set short-circuit & edge redirects (cost)
vumbnail-accountsaccounts.vumbnail.com/*Stripe webhook → entitlement sync (KV + D1 + GitHub)
vumbnail-astro-siteastro.vumbnail.com/*marketing site; thumbnail Worker passes non-thumbnail paths here
vumbnail-animated-thumbnail-rendererservice bindingWASM animated rendering (flagged)
vumbnail-video-metadata (consumer)queuemetadata observation (flagged)
playlist-resolver(-worker)external resolverresolves unknown YouTube playlists
API / dashboardstarter-kit routesoperator metrics + auth (mostly internal)

Public R2 is exposed at cache.vumbnail.com; the edge Snippet redirects hot watermarked traffic there, and a WAF rule blocks …/clean.jpg.

  • watermark-test.vumbnail.com — thumbnail Worker with animated thumbnails and debug enabled.
  • relay-test.vumbnail.com — forces Vimeo relay-only mode, separate R2 prefix.
  • accounts-staging.vumbnail.com, accounts-preview.vumbnail.com — webhook staging/preview.

legacy-vumbnail-vercel-api, legacy-vumbnail-video, and legacy-vumbnail-worker-canary are retained from the Vercel era; moving the last /6* canary routes fully onto Cloudflare is a roadmap item.

Thumbnail Worker: THUMBNAIL_BUCKET (R2), THUMBNAIL_CONFIG (KV), ASSETS (watermark.png + fallbacks), IMAGES (legacy transform), SITE_PASSTHROUGH_SERVICE (→ Astro site), ANIMATED_THUMBNAIL_RENDERER (service binding), VIDEO_METADATA_QUEUE (producer), plus VERSION_METADATA.

Accounts Worker: PROCESSED_EVENTS_STORE (KV), THUMBNAIL_CONFIG (KV, shared), BILLING_ENTITLEMENTS_DB (D1); secrets STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, GH_TOKEN.

Browser → vumbnail.com/<id>.jpg
▼ Cloudflare edge Snippet (watermark-router)
├─ paying domain/IP? → pass through ──┐
├─ /.jpg malformed? → 308 error.jpg │
├─ Borås loop? → 307 wm.jpg │
├─ hot id + wm referrer? → 307 cache.vumbnail.com/.../wm.jpg
└─ else → pass through ──┤
vumbnail-thumbnail Worker
├─ parse id/size/password
├─ watermark decision (clean | wm)
│ └─ KV entitlement projection (paid bypass)
├─ edge cache → R2 variant → R2 clean→wm
└─ miss: resolve source (Vimeo/YouTube/relay)
→ store R2 → cache → respond
  • Per-app deploys via Wrangler (bun --filter @repo/<app> deploy); the Snippet has its own deploy / verify-hotset / smoke / rollback:snapshot.
  • The thumbnail Worker ships with a predeploy route-safety guard and ramps by percentage (0 → 1 → 5 → 10 → 25 → 50 → 100) with a health-check suite.
  • Multi-worker deploy safety is enforced by scripts/cloudflare checks so one app’s deploy can’t clobber another’s routes.
  • The hard cost guardrail applies to every deploy: ≥ $1/month of new Cloudflare spend requires a written estimate in docs/ first.