Files
linearvoid/docs/operations/cloudflare-workers-setup.md
T
zwitschi d8cf853842
Release / release (push) Successful in 1m15s
CI / test (push) Successful in 2m53s
CI / docker (push) Successful in 2m0s
chore(release): 1.1.0
- playout: run-scoped R2 manifest URIs (candidate a rewrite via rewriteManifestToRun)
- tests: playlist_rewrite_test.go (rewrite + publish integration + slate guard)
- docs: STREAMING, cloudflare-workers-setup, architecture (incl. Level-2 diagram)
- release housekeeping: TODO->DONE, CHANGELOG 1.1.0, version bump
2026-09-03 09:27:38 +02:00

5.0 KiB

Cloudflare Workers Setup — Linear Void

Linear Void uses Cloudflare Workers for two purposes:

Product Purpose What
Workers Static SPA hosting linearvoid-frontend (frontend/wrangler.toml) — Vite SPA (frontend/dist) static assets
Workers Edge HLS delivery linearvoid-media (infrastructure/cloudflare/) — R2-bound Worker on media.linearvoid.tv

Both are managed under Workers & Pages in the Cloudflare dashboard.

Dashboard URLs

Resource URL
Workers & Pages overview https://dash.cloudflare.com/deb11491c54ec53a24772e98ac6d8128/workers-and-pages
Worker: linearvoid-media https://dash.cloudflare.com/deb11491c54ec53a24772e98ac6d8128/workers/services/view/linearvoid-media/production/settings
API tokens https://dash.cloudflare.com/profile/api-tokens

Worker: linearvoid-media (edge HLS delivery)

The Worker in infrastructure/cloudflare/ runs on the linearvoid-media Workers service. It owns the media.linearvoid.tv host, serves HLS objects from the R2 bucket (bound as MEDIA_BUCKET), and stamps immutable Cache-Control on segments plus a short TTL on live manifests (CORS + Range supported). See its README.

Run-scoped layout. R2 objects are stored run-scoped (hls/r-{runID}/seg-*.m4s, …/init.mp4), and the live hls/playlist.m3u8 references them with the run prefix (the playout rewrites bare URIs before publishing — see docs/STREAMING.md). The Worker is a faithful path→R2 mapper: it serves whatever key the request path resolves to (e.g. /hls/r-…/seg-*.m4s), adds the cache headers by file type, and does not rewrite manifest URIs at serve time.

Test / deploy:

cd infrastructure/cloudflare
npm install && npm test              # unit + Miniflare R2 tests
npx wrangler deploy                  # preview/test target
npx wrangler deploy --env production # attach media.linearvoid.tv

Attach the production custom domain only after removing media.linearvoid.tv from the R2 bucket's direct custom-domain binding. Automated production deploy: .gitea/workflows/workers-media-deploy.yml.

Worker: static frontend

Serve the Vite-built SPA (frontend/dist) as Worker static assets:

  1. Build the frontend: cd frontend && npm run build.
  2. Bind frontend/dist to the Worker as static assets (Workers Static Assets / assets in wrangler.toml).
  3. Attach the linearvoid.tv custom domain to the Worker.

See gitea-cloudflare-workers.md for the automated deployment workflow.

Build-time variables

The VITE_PUBLIC_* values are baked into the bundle at build time by Vite (vite.config.ts uses envDir: ".." to read them from the repo root). They are supplied by the Gitea Actions build environment from Gitea secrets — not as Worker runtime variables. The static-assets Worker has no runtime JavaScript, so it reads no env at request time.

Name Value
VITE_PUBLIC_APP_URL https://linearvoid.tv
VITE_PUBLIC_WS_URL wss://linearvoid.tv/ws
VITE_PUBLIC_HLS_URL https://media.linearvoid.tv/hls/playlist.m3u8
VITE_PUBLIC_ADMIN_DEFAULT_MODERATOR boogers
VITE_PUBLIC_ADMIN_DEFAULT_ROOM main
VITE_PUBLIC_ADMIN_MODERATION_LOG_LIMIT 50

Backend services (playout, chat, nginx) read their own runtime variables (ADMIN_*, HLS_*, PLAYLIST_PATH, R2_*, DATABASE_URL, REDIS_URL) from the container environment — see .env.example.

Custom domains

  • linearvoid.tv → Worker (static SPA, linearvoid-frontend)
  • www.linearvoid.tv → redirect to linearvoid.tv
  • media.linearvoid.tv → Worker (linearvoid-media, R2-bound) serving the linearvoid-media bucket