Skip to content
Seal
Esc
↑↓navigate↵open⌘Jpreview
On this page

Self-host on Cloudflare

Deploy Seal on your own Cloudflare account with D1, R2, and workers.dev

Self-host on Cloudflare

Run Seal on your Cloudflare account. Signing loop works with Workers + D1 + R2. No Vortex resource IDs. No Docker compose.

Deploy to Cloudflare

Deploy to Cloudflare

Seal is a pnpm monorepo. On the Workers Builds setup screen:

Field Value
Root directory /
Build command pnpm install
Deploy command pnpm selfhost

Requires Node 24+, pnpm 12+, and a Cloudflare account.

git clone https://github.com/VortexNYC/seal.git
cd seal
pnpm install
pnpm exec wrangler login
pnpm selfhost

Non-interactive secrets:

BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
TOKEN_HASH_SECRET=$(openssl rand -base64 32) \
INTERNAL_API_KEY=$(openssl rand -base64 32) \
pnpm selfhost

What the script does:

  1. Prompts for (or reads) the three secrets above
  2. Deploys apps/api [env.selfhost] — wrangler auto-provisions D1 + R2
  3. Applies D1 migrations by binding name (D1)
  4. Sets BETTER_AUTH_URL / APP_URL / ALLOWED_ORIGINS to your *.workers.dev URLs
  5. Builds and deploys apps/web against that API

You get something like:

Web:  https://seal-web.<account>.workers.dev
API:  https://seal-api.<account>.workers.dev

Cold-account checklist (stranger-shaped)

Treat a new Cloudflare login as the real proof. Vortex-account dogfood is safe (seal-selfhost-* names) but does not prove stranger readiness.

Do these in order; stop when one fails.

  1. Clone + install on a clean machine (no prior wrangler login, no copied Vortex .dev.vars):
    git clone https://github.com/VortexNYC/seal.git && cd seal
    pnpm install
    pnpm exec wrangler login   # *your* account
    pnpm selfhost
  2. Open the printed web URL → sign up → verify email → create a workspace
  3. Developer → API Keys → create seal_…
  4. Golden path (CLI + public signing half → completed → audit):
    SEAL_API_KEY=seal_… pnpm run prove:golden-path \
      --api https://seal-selfhost-api.<account>.workers.dev \
      --app https://seal-selfhost-web.<account>.workers.dev
    Alternate raw HTTP smoke (no CLI):
    SEAL_API_KEY=seal_… node scripts/smoke-prod.mjs \
      --api https://seal-selfhost-api.<account>.workers.dev
  5. Sign once in a real browser from the signing_url (or the UI) so you trust the SPA route, not only the public API harness
  6. Email — only after the loop above is green (see next section)

If step 1–4 fail on a cold account, that is a product bug — fix docs/script before claiming self-host works.

Email (required for real invites)

selfhost ships with a Cloudflare Email Sending binding (EMAIL). Signing links still work from the UI/API without mail; invites need a verified sender domain on your Cloudflare account.

  1. Enable sending for your domain: pnpm exec wrangler email sending enable your-domain.com
  2. Set allowed_sender_addresses / EMAIL_FROM under [env.selfhost] in apps/api/wrangler.toml to an address on that domain
  3. Redeploy: pnpm --filter @seal/api exec wrangler deploy --env selfhost

Vortex dogfood uses noreply@seal.nyc (domain already enabled on the account).

Optional workers

Worker Needed for
API + web Core upload → send → sign
anydoc Rich PDF field detection
convert DOCX → PDF (Containers)
mcp Agent MCP surface on your origin

PDF upload and signature collection work without anydoc/convert.

Custom domains

Start on *.workers.dev. When you own DNS, add routes under [env.selfhost] (or promote to a dedicated production env with your own D1/R2 IDs — never reuse Vortex’s).

Local development

For laptop-only work (no deploy):

cp apps/api/.dev.vars.example apps/api/.dev.vars
cp apps/web/.env.example apps/web/.env.local
pnpm run dev

See the repo CONTRIBUTING.md.

Safety

Selfhost worker / D1 / R2 names are seal-selfhost-* so they cannot overwrite hosted production (seal-api, seal-web, seal-global, seal-documents). You can dogfood on the Vortex account; for a customer-shaped cold proof, use a separate Cloudflare login.

Was this page helpful?