A multi-tenant SaaS platform for building, publishing, and managing websites at franchise scale — powered entirely by Cloudflare's edge infrastructure.
PageKiln is a franchise-ready website engine. HQ manages templates and the platform. Franchisees each get their own site with a custom domain, CMS, and inline editor — all on one shared infrastructure.
The brain. Hono REST API handling auth, content management, domain provisioning, build orchestration, and static site serving — all in one Cloudflare Worker.
Cloudflare WorkersNext.js 16 operator UI deployed as a Cloudflare Worker via OpenNext. Manages domains, content, publishing, templates, and team members.
Next.js + OpenNextNode.js process on a VPS. Polls for build jobs, runs the Astro site generator, uploads static files to R2 object storage. The only component not on Cloudflare.
VPS / Node.jsCloudflare's serverless SQLite. Stores tenants, users, sessions, content blocks, domains, releases, audit logs, and the franchise org hierarchy.
Relational DataHOSTMAP_KV maps hostnames to tenants — the routing table for "which domain is which site." FORM_RL_KV tracks rate limits for signups and form submissions.
Key-ValueS3-compatible object storage holding all published site artifacts. Structure: sites/{tenantId}/{version}/**
Cloudflare Queues for async job dispatch. When a user clicks "Publish," a message is enqueued. The Runner picks it up, builds the site, and reports back.
Cloudflare QueuesCloudflare's Postgres connection pooler + query cache. Connects to an external Neon database for tenant data connectors and collection schemas.
CF Hyperdrive + NeonCloudflare API feature that provisions individual SSL certificates for every tenant's custom domain. Handles DNS verification, certificate issuance, and renewal automatically.
CF Custom HostnamesWYSIWYG overlay on the live published site. Activated via ?edit=1 URL param or Cmd+E. Uses short-lived editor tokens (max 24h).
Every request passes through these layers. The edge routing decides which Worker handles it, the Worker talks to the data layer, and the Runner builds sites asynchronously.
platform.onepointcode.com → Platform
app.onepointcode.com → Dashboard
www.mybusiness.com → catch-all
fallback: platform.onepointcode.com
*/* on zone. Catches all unmatched traffic including custom hostname requests.
*/* → Platform Worker
/api/*) for dashboard + runner, OR static site server (Host header → KV → R2). Also handles queue messages and 5-min cron for domain sync.
pagekiln-platform-worker-staging
pagekiln-dashboard-staging
pagekiln-staging
host:example.com → {tenantId, tz}
signup_rl:{ip}:{hour}
sites/{tenant}/{version}/**
pagekiln-build-jobs
external DB
/api/runner/jobs/claim every 5s. Claims build jobs, runs Astro with the selected template, generates static HTML/CSS/JS, uploads artifacts to R2.
pnpm runner
The journey from clicking the button to a live website, in 7 steps.
User clicks "Publish" in the dashboard. POST to /admin/site/publish.
Worker creates a build job in D1 and pushes a message to the Build Queue.
Runner polls the API, claims the job. Status moves to "running."
Astro generates the static site using the selected template + CMS content.
Static files pushed to R2 under sites/{tenant}/{version}/.
Worker creates a release, marks it active, updates HOSTMAP_KV.
Next visitor request is served the new version from R2. Done.
From the browser's address bar to a fully rendered page — every hop.
https://www.mybusiness.com/aboutplatform.onepointcode.com. SSL cert issued via Custom Hostname.*/* sends to Platform Worker.www.mybusiness.com. Not an API path, so enters static site serving mode.host:www.mybusiness.com from HOSTMAP_KV → {"tenantId":"t_pizza1","timezone":"US/Eastern"}2026-03-11T15:30:00Zsites/t_pizza1/2026-03-11T15:30:00Z/about/index.html from R2 bucket.Cache-Control: max-age=60. Hashed assets are immutable.The platform supports multi-level organizations. HQ at the top, franchise owners in the middle, individual business sites at the bottom.
Every major component at a glance.
Hono REST API. Auth, CMS, domains, publishing, site serving, queue handler, scheduled cron. The core of everything.
Next.js operator UI. Content editing, domain management, template selection, team management, audit logs.
VPS process that claims build jobs and runs the Astro static site generator. Uploads results to R2.
Relational database. Tenants, users, content blocks, domains, releases, forms, franchise hierarchy, audit trail.
Maps host:domain.com → {tenantId, timezone}. The routing table that connects custom domains to sites.
S3-compatible. Stores every version of every site: HTML, CSS, JS, images. Immutable versioned paths.
Cloudflare Queues. Dashboard enqueues build jobs, Runner dequeues them. Decouples the "publish" click from the actual build.
Cloudflare's Postgres connection pooler + edge cache. Accelerates queries to an external Neon database for data connectors.
CF API that provisions SSL for tenant domains. Auto-renewing certs, DNS verification, domain lifecycle management.
WYSIWYG overlay on the published site. Cmd+E or ?edit=1. Token-based auth, publishes directly from the live page.