Skriuw Documentation
Self-hosting and operations

Collaboration setup

Deploy the Cloudflare Worker that powers realtime collaboration and wire it to the app with a shared HMAC secret and the WebSocket host.

Realtime collaboration runs on a Cloudflare Worker, not the app server or the Docker stack. Until you deploy that Worker and point the app at it, collaboration stays disabled and the rest of the app works normally.

Components

  • The Worker in apps/collab/notes.ts, configured by apps/collab/wrangler.jsonc. It runs Yjs over a WebSocket and verifies each connection in onBeforeConnect.
  • The Next app, which signs a room token per note and sends it to the browser.

The Worker and the app share one HMAC secret. The app signs tokens with it, the Worker verifies them. If the two values differ, every socket returns 401 and nothing syncs.

Local development

Run the Worker with wrangler:

bun run party:dev

It serves on 127.0.0.1:8787. Set the app env:

NEXT_PUBLIC_PARTYKIT_HOST="127.0.0.1:8787"
COLLAB_AUTH_SECRET="<same value as the worker>"

Put the same COLLAB_AUTH_SECRET in .dev.vars (gitignored) so the local Worker reads it.

Production

Deploy the Worker:

bun run party:deploy

The deploy prints the Worker host, in the form <worker-name>.<subdomain>.workers.dev. Set the secret on the Worker and the host on the app:

bunx wrangler secret put COLLAB_AUTH_SECRET -c apps/collab/wrangler.jsonc   # same value used to sign tokens
NEXT_PUBLIC_PARTYKIT_HOST="<worker-name>.<subdomain>.workers.dev"
COLLAB_AUTH_SECRET="<same value as the worker>"

NEXT_PUBLIC_PARTYKIT_HOST is inlined at build time. On a prebuilt Docker image it is frozen, so a self-host image that ships collaboration needs the host baked in at build. See Self-host with Docker.

Disable

Leave NEXT_PUBLIC_PARTYKIT_HOST blank. This is the default in .env.example. A non-empty value pointing at a Worker that is not running makes every socket return 401, so keep it blank unless the Worker is live.

On this page