Skip to content

← Back to standards

Cloudflare

Cloudflare is our front door on the internet. When someone visits a Brytebridge website or calls an API, they usually meet Cloudflare first. Cloudflare handles the public address, security at the edge, and routing traffic to the right place behind the scenes.

We use it so our apps do not sit wide open on the public internet—and so marketing pages and docs load fast without running servers we have to babysit.

Last updated: May 22, 2026


Cloudflare does two big jobs for us:

JobPlain EnglishWhere the work actually runs
Static sitesPages and docs that are just files (HTML, images, PDFs)—no always-on serverCloudflare (edge hosting)
APIsLive services that need a running processFly.io (Fly.io standards) — Cloudflare only routes traffic in

That split keeps things simple: files at the edge, programs in Fly.

Static sites (docs, marketing)

If it does not need a CPU running 24/7, we put it on Cloudflare—standards sites, marketing pages, and similar content.

Fast, cheap, and nothing to patch like a traditional server.

APIs (the tunnel pattern)

Our APIs run on Fly.io, but users and partners do not call a public Fly URL. Instead, each API opens a private tunnel out to Cloudflare. Cloudflare is the only public entry point.

Think of it like a one-way door: the app connects out to Cloudflare; the internet does not knock directly on Fly.

Security rules (who can reach staging vs production, bots, geography, etc.) live in Cloudflare, not on an open API port.

Fly side (no [http_service], org-specific tunnel, each app registers): Fly tunnel standards.

We try to keep Cloudflare easy to recognize and easy to audit:

  • Use the repo name as the mental model for the service—e.g. penn-station-api, usfs-api, creed-api. Fly app names and tunnel service names follow that pattern so anyone can map GitHub → Fly → Cloudflare without a secret lookup table.
  • Prefer one tunnel “app” in Cloudflare when we can—e.g. a shared production tunnel—then add separate public hostnames inside it for staging and production (and UAT when we use it). Staging and production stay different hostnames and different Fly apps; they should not share one catch-all rule that could send traffic to the wrong environment.
  • Each environment gets its own row: public hostname (what users type) → private origin (the Fly app on the internal network, port 8080).

Staging

Staging hostname (often a clear prefix, e.g. s- or staging.)

Points at the staging Fly app for that repo

UAT

UAT hostname when we run a UAT tier

Points at the UAT Fly app

Production

Production hostname (the “real” customer URL)

Points at the production Fly app

Example (conceptual): one shared tunnel, two hostnames for the same product—s-api-portal… for staging and api-portal… for production—each aimed at the correct Fly app name, not at a generic “localhost” target.

What you configure (checklist in plain language)

Section titled “What you configure (checklist in plain language)”

When onboarding or reviewing a service, these are the Cloudflare-side pieces—not the Fly deploy itself:

  1. Tunnel — Usually under Zero Trust → NetworksTunnels. We reuse a shared tunnel where it makes sense; each API still gets its own hostname row.
  2. Public hostname — The URL the world uses (must match DNS).
  3. Service / origin — Where Cloudflare sends traffic inside Fly (the app’s internal name, port 8080).
  4. DNS — A proxied record (orange cloud) so the hostname hits the tunnel.
  5. Access & WAF — Rules so real clients can reach the API and bots do not block legitimate traffic by mistake.
  6. Tunnel token — Copied from Install connector and stored on the Fly app as CLOUDFLARE_TUNNEL_TOKEN (see Fly checklist — Fly environment variables).

Platform or tech lead should sign off when a new public hostname goes live.

These are the names people actually see in dashboards and secrets—nothing exotic:

SettingWhere it livesWhat it’s for
Public hostnameCloudflare tunnel → Public HostnameThe customer-facing URL (staging vs prod are different hostnames)
Service / originSame rowWhich Fly app receives traffic (matches repo / Fly app naming)
DNS recordCloudflare DNSConnects the hostname to the tunnel (proxied)
CLOUDFLARE_TUNNEL_TOKENFly secret (per Fly app)Lets the running container register with the tunnel—set once per tier’s Fly app

For APIs, Fly holds the token; Cloudflare holds the hostnames and rules. GitHub deploy does not replace tunnel setup—you still need hostname + DNS + token aligned with the Fly app for that tier.

For docs and marketing we use Cloudflare Pages (or equivalent static hosting on Cloudflare):

  • Connect the GitHub repo (often the same repo name as the project).
  • Production branch is usually main; preview branches can represent staging work.
  • No tunnel token—there is no Fly process, only files at the edge.

This standards site (fly-standards) is an example of content that can live on Cloudflare as static HTML after build, while API repos stay on Fly behind a tunnel.

User → Cloudflare (hostname, TLS, security) → Tunnel → Fly app (API code)
  • Fly.io — runs the container, health checks, metrics, logs to Grafana.
  • GitHub — deploys to Fly; does not replace Cloudflare hostname setup.
  • Fly checklist — tier checklists plus GitHub and Fly secret panels.
  • Fly.io — APIs, tunnels from the Fly side, three orgs per tier
  • Fly checklist — promotion checklist and required secrets
  • Zero Trust — why we segment environments and minimize access