Skip to content

Self-Hosting

Typeroll is open-source (MIT) and can be self-hosted. This guide covers running the portal on your own infrastructure.

Portal (Astro SSR) ──────▶ Firestore (content)
│ R2 / S3 (media CDN)
▼ Cloudflare Pages (static site output)
Static site builder (Astro SSG)
  • Node.js 20+
  • Firebase project with Firestore and Authentication enabled
  • Cloudflare account with R2 for media storage and Pages for site output
  • Anthropic API key for the AI chat feature

Clone the repository and install dependencies:

Terminal window
git clone https://github.com/typeroll/typeroll
cd typeroll
npm install

The portal includes a fixtures backend — a JSON file store that replaces Firestore for local development. No Firebase configuration needed to run locally:

Terminal window
npm run dev:portal

Open http://localhost:4321. You’ll be logged in as a dev user with access to the sample content in packages/portal/fixtures/.

For production, create a .env file in packages/portal/:

# Firebase (required for auth in production)
FIREBASE_SERVICE_ACCOUNT={"type":"service_account","project_id":"..."}
# AI chat
ANTHROPIC_API_KEY=sk-ant-...
# Media CDN (Cloudflare R2 or any S3-compatible store)
R2_ACCOUNT_ID=...
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET=typeroll-media
R2_PUBLIC_BASE_URL=https://cdn.yourdomain.com
# Static site output (Cloudflare Pages)
CLOUDFLARE_ACCOUNT_ID=...
CLOUDFLARE_API_TOKEN=...
CLOUDFLARE_PAGES_PROJECT=your-pages-project
# Security
FORMS_HMAC_SECRET=a-random-64-char-hex-string
PREVIEW_HMAC_SECRET=another-random-64-char-hex-string
# Portal URL (used in deploy output and preview links)
PORTAL_PUBLIC_URL=https://app.yourdomain.com
SITES_BASE_DOMAIN=sites.yourdomain.com
# Deploy queue (in_process for single-server; cloud_tasks for production scale)
DEPLOY_QUEUE=in_process
  1. Create a Firebase project at console.firebase.google.com
  2. Enable Firestore (Native mode) and Authentication (Email/Password)
  3. Create a service account: Project Settings → Service Accounts → Generate new private key
  4. Set FIREBASE_SERVICE_ACCOUNT to the full JSON content (one line)
  5. For each user, set an org_id custom claim via the Firebase Admin SDK:
await admin.auth().setCustomUserClaims(uid, { org_id: "your-org-id" });

All content is scoped under organizations/{org_id}/ in Firestore.

A Dockerfile is included at the repo root:

Terminal window
docker build -t typeroll-portal .
docker run -p 4321:4321 --env-file .env typeroll-portal

The included GitHub Actions workflow (.github/workflows/deploy.yml) deploys to Google Cloud Run. See the workflow file for the full configuration — it uses Workload Identity Federation (no long-lived service account keys).

For other platforms (Fly.io, Railway, etc.), the portal is a standard Node.js SSR application. Set all the environment variables and run node dist/server/entry.mjs.