Whitelabel: running this service as another org's own
This service is a SaaS-shaped product: one checkout + one
wrangler.toml + one instance YAML = one org's status site. The
engine is estate-agnostic; nothing about the chrome, the registry, the
feeds, or the admin carries a brand you did not declare. This is the
runbook for standing up your own.
The five steps
Declare your instance in
config/status.yaml(the full field contract:docs/config-schema.md):site: name: Acme Status base_url: https://status.acme.example description: The live status of every Acme service. logo: light: https://www.acme.example/brand/logo.svg dark: https://www.acme.example/brand/logo-white.svg links: - label: Acme href: https://www.acme.example/ source_url: https://github.com/acme/status fonts_url: https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap theme: --accent: "#0f766e" --ink: "#1c1917" groups: [Platform, Website] vantages: { relay_stale_ms: 300000, list: [{id: home, kind: home, label: home, description: the status worker's own scheduling location}] } services: - id: website # ... every surface you probe, with its content assertionsite.fonts_urlreplaces the self-hosted estate font stack (absent, the page serves its own OFL woff2 subset from/fonts/with zero third-party requests);site.themeoverrides design tokens (hex / rgb colors only — the loader refuses anything that could carry CSS). Migrating a registry that still lives in TypeScript?scripts/convert-registries.tsdoes it mechanically.Your manifest: copy
wrangler.example.tomltowrangler.toml, name your worker, create + wire your KV namespace. The relay (the second vantage) is optional: copywrangler.relay.tomlalongside and share theSTATUS_RELAY_TOKENsecret on both sides. The plan matters: a per-minute multi-vantage prober is a paid-tier workload by design — on the Workers FREE plan the 1,000 KV writes/day quota dies ~70 minutes after midnight UTC and the page honestly goes stale for the rest of the day (the playbook:docs/manual/04-operations.md). Budget Workers Paid before going live.Deploy:
npm run deploy(andnpm run deploy:relay), with your Cloudflare token + account id in the environment. Then attach your domain:bash scripts/attach-custom-domain.sh— it derives the hostname and zone from yourbase_url.Operate: set the secrets —
OPS_TOKEN(the admin + ops gate),STATUS_RELAY_TOKEN(if you run the relay),MAIL_PROVIDER_KEY+ themail:block (the subscribe surface stays an honest 503 without one). The admin interface (/admin, login withOPS_TOKEN) is your runtime operate path: publish the automation's drafts, compose incidents, drive the update trail. The git-PR path (incidents/*.md) stays available as the strongest review posture.Watchdog: the heartbeat workflow runs from this repo's GitHub Actions against your
base_url— enable Actions, and the one-canonical-issue alert lifecycle is live with no secrets.
The whole surface is yours
A whitelabel instance runs the FULL product, not a reduced one: the
public board with its uptime windows and the per-service latency
drill-down (/latency/<id>), the embeddable /badge.svg, RSS/Atom
- email subscriptions + webhook channels, the token-or-identity
admin (
admin.oidcpoints at YOUR identity provider — any conformant OP; discovery, never hardcoded endpoints; anorgblock turns on per-org members, roles, and invites), the write API for your automation (docs/api.md), backups/restores (docs/manual/05-backups.md), the chrome words in your language (site.locale+site.strings), the heartbeat dead-man's switch, named per-org API keys, and the page-provisioning emission (draft a complete new instance from a form). One YAML declares all of it.
What is NOT yours to assume
- The honest postures are the product, not a skin: a green always means the user's path works; a silent vantage reads UNKNOWN; maintenance never feeds uptime; percentages truncate; drafts never render or mail. A whitelabel instance inherits all of it.
- Licensing: this repository is private today. An org running their own instance needs the owner's grant — that decision is the owner's, not a file in this repo.
Two deployment postures
- Own deployment (the flagship posture): one repo, one
config/status.yaml, the build compiles the instance. The whitelabel seam is the shell. - Shared deployment: many pages on one deployment, registered
through the page registry (
docs/manual/07-shared-deployments.md) or the control plane's emitted YAML. The quota ceiling is the sum of the pages' services x vantages — Workers Paid is a prerequisite for the deployment, not per page.
The runtime overrides (TODO 78)
The config declares the identity; the console can also carry it at run time: the Design register (owner-gated, page-scoped) uploads a logo pair and layers hex-only theme tokens over the config theme. The config file stays the source of truth for everything else — fonts, links, the strings — and the runtime rows ride in the backup like every other register.