Cloudflare Pingora Architecture Diagram: How Tako Routes Requests, TLS, and Cold Starts

Cloudflare Pingora Architecture Diagram: How Tako Routes Requests, TLS, and Cold Starts

Tako-kun ·

Pingora is not a config file with a proxy hiding behind it. It is a Rust framework for building programmable network services, which is exactly why we use it in Tako.

In our Pingora vs Caddy vs Traefik post, we talked about the decision. This post is the wiring diagram: what actually happens when a browser request hits a Tako server, how TLS is selected, where route matching happens, when the proxy serves a file directly, and how a scaled-to-zero app wakes up before the request is forwarded.

If you came here looking for a Cloudflare Pingora architecture diagram, this is not Cloudflare’s internal edge. This is Tako’s edge path, built on the same programmable proxy framework.

The request path in one diagram

Pingora’s ProxyHttp lifecycle is built around hooks: inspect the request, choose an upstream peer, adjust the upstream request, observe the response, and log the result. Tako uses those hooks as the edge control plane for deployed apps.

Diagram

The important part is where the decisions live. Tako does not generate an Nginx config, reload an external proxy, and hope the process manager agrees. The Pingora proxy, route table, load balancer, TLS manager, static file path, cold-start manager, and app process state all live in the same server process.

That is why features like zero-downtime deploys, scale-to-zero, and multiple apps on one VPS are not separate layers. They are all request-path decisions.

TLS happens before app routing

The first choice is not “which app gets this request?” It is “which certificate should the listener present?”

For HTTPS, the browser sends SNI during the TLS handshake. Tako’s TLS layer asks the certificate manager for an exact hostname match first, then tries a wildcard certificate match, then falls back to a default self-signed certificate when no matching certificate exists yet. That fallback lets the TLS handshake complete so the HTTP layer can return a normal status like 404 for an unknown host.

Certificate behavior is tied to routes in tako.toml:

Route shapeCertificate behavior
example.comACME HTTP-01 certificate for the exact hostname
api.example.comACME HTTP-01 certificate for the exact hostname
example.com/docs/*Uses the example.com certificate
*.example.comWildcard certificate through Cloudflare DNS-01

HTTP requests normally redirect to HTTPS with a 307, except for /.well-known/acme-challenge/*, which the proxy handles directly so Let’s Encrypt can verify the domain. Wildcard routes are the special case: they require Cloudflare DNS-01 credentials because HTTP-01 cannot prove control of every possible subdomain. The deploy flow checks that before shipping the app.

So by the time Tako starts thinking about apps, TLS is already settled. The request is inside Pingora’s HTTP lifecycle with a host, path, headers, and a per-request context.

Route matching is pure host and path

Tako’s route table is intentionally simple. Deployed apps contribute environment-level routes, and incoming requests are matched by hostname and path. The most specific match wins: exact host beats wildcard host, and longer path beats shorter path.

name = "docs"
runtime = "bun"

[envs.production]
routes = [
  "example.com/docs/*",
  "docs.example.com"
]
servers = ["prod"]

The route table accepts four useful shapes:

RouteWhat it matches
api.example.comExact hostname
*.example.comAny one matching subdomain
example.com/api/*Hostname plus path prefix
*.example.com/admin/*Wildcard hostname plus path prefix

Once request_filter has the selected app, it handles edge-owned responses before forwarding to an app process.

First, /_tako/* is reserved for Tako’s public endpoints. Durable channels, image optimization, and signed storage URLs live there. Those requests are not ordinary app routes.

Second, static assets get a fast path. If a request looks like a file, Tako checks the deployed app’s public/ directory and serves the file directly when present. For path-prefixed routes, it also tries the prefix-stripped asset path. That is why an app mounted at example.com/docs/* can still serve a built asset like /assets/main.js when the browser asks for /docs/assets/main.js.

Only after those checks does the proxy need a backend process.

Cold starts are backend resolution

Backend resolution asks a narrow question: is there a healthy instance for this app?

If yes, Tako selects one. If not, the answer depends on the app’s desired instance count. For an always-on app, no healthy backend is an outage, so production returns a generic 503 Service Unavailable and logs the app-scoped diagnostic. For an app that has been scaled to zero, no healthy backend is the wake-up path.

The cold-start manager uses a leader/waiter pattern:

SituationProxy behavior
First request arrives while app is at zeroBecomes the leader and starts one instance
More requests arrive during startupWait behind the same cold start
Startup succeedsWaiters continue to the new healthy backend
Startup exceeds 30 secondsReturn 504 Gateway Timeout
Spawn or readiness failsReturn 502 Bad Gateway
More than 1000 requests waitReturn 503 Service Unavailable

The app process itself is still a normal native process. Tako sets HOST=127.0.0.1 and PORT=0, then the SDK binds an OS-assigned port and reports it back over file descriptor 4. The server probes the SDK status endpoint, marks the instance healthy, records cold-start metrics, and releases the waiting requests.

There is no container image to unpack and no external proxy config to rewrite. The request that discovered the app was cold is the same request that waits for the instance to become routable.

Upstream proxying is the last step

Once a backend is ready, Tako’s load balancer chooses a healthy instance with round-robin selection. The selected instance has a loopback endpoint like 127.0.0.1:47831, and Pingora’s upstream_peer hook turns that into the actual upstream connection.

Before forwarding, Tako adjusts the upstream request:

Header or fieldWhat Tako does
X-Forwarded-ProtoSets https or http based on the effective request
X-Forwarded-ForSets the resolved client IP when trusted
ForwardedRemoves it before proxying
X-Tako-Internal-TokenRemoves client-supplied values
Request bodyEnforces the configured body-size limit

When response headers arrive, Tako records upstream timing. When the request finishes, it releases per-IP rate-limit accounting, marks the selected instance request as finished, records end-to-end request metrics, and logs the final status.

That is the full shape: SNI first, route table second, Tako-owned endpoints and static assets before app traffic, cold-start backend resolution when needed, then loopback proxying to a healthy native process.

Why this architecture matters

A standalone reverse proxy is great when routing is the whole job. Tako’s proxy has a different job. It needs to know whether a deploy is rolling out, whether an instance is healthy, whether a route belongs to a static asset, whether a request should wake a sleeping app, and whether a wildcard hostname needs DNS-01 certificate handling.

Pingora gives us the programmable request lifecycle for that. Tako supplies the app model around it: tako.toml, tako deploy, local HTTPS in tako dev, encrypted secrets, runtime readiness, workflows, channels, and image optimization.

The result is a small edge inside your VPS: one Rust server process that terminates TLS, routes requests, manages app instances, and keeps the proxy aware of the deployment state it is serving.