Proxy Architecture¶
This document describes the internal architecture of the L7 proxy data plane.
Overview¶
The proxy sits between cloudflared tunnel transport and backend Kubernetes services. It implements full Gateway API HTTPRoute routing locally, removing the limitations of Cloudflare's tunnel ingress API.
flowchart LR
subgraph Proxy Binary
CFD[cloudflared<br/>supervisor]
OP[OriginProxy]
HANDLER[Handler]
ROUTER[Router]
FILTER[Filters]
BACKEND[Backend Pool]
end
CFD -->|ProxyHTTP| OP
OP -->|ServeHTTP| HANDLER
HANDLER --> ROUTER
ROUTER -->|match| FILTER
FILTER -->|proxy| BACKEND Packages¶
internal/
├── proxy/
│ ├── config.go # ProxyConfig, RouteRule, RouteMatch types
│ ├── matcher.go # Path/header/query/method matchers
│ ├── router.go # Routing table with atomic config swap
│ ├── filter.go # Request/response filters (headers, redirect, rewrite, mirror)
│ ├── handler.go # http.Handler: match → filter → proxy → response filter
│ ├── api.go # Config API (PUT/GET /config, /healthz, /readyz)
│ ├── converter.go # Gateway API HTTPRoute → proxy config conversion
│ └── pusher.go # HTTP client for pushing config to proxy replicas
│
├── tunnel/
│ ├── origin.go # GatewayOriginProxy (connection.OriginProxy)
│ └── bootstrap.go # Tunnel startup, token parsing, supervisor config
│
└── cmd/proxy/
└── main.go # Binary entry point (tunnel mode / standalone mode)
Request Flow¶
sequenceDiagram
participant Edge as Cloudflare Edge
participant CFD as cloudflared
participant OP as OriginProxy
participant H as Handler
participant R as Router
participant F as Filters
participant B as Backend
Edge->>CFD: QUIC/HTTP2 tunnel
CFD->>OP: ProxyHTTP(writer, request)
OP->>H: ServeHTTP(w, r)
H->>R: Route(request)
R-->>H: matched rule + backend index
H->>F: Apply request filters
alt Redirect filter
F-->>H: redirect response
H-->>OP: write redirect
else Normal flow
F-->>H: modified request
H->>B: Select weighted backend
B-->>H: reverse proxy response
H->>F: Apply response filters
F-->>H: modified response
H-->>OP: write response
end
OP-->>CFD: done
CFD-->>Edge: response Routing Table¶
The router uses atomic.Pointer[routingTable] for lock-free reads during config updates:
- Exact hosts:
map[string][]*compiledRulefor O(1) hostname lookup - Wildcard hosts:
[]wildcardEntryfor*.example.compatterns - Default rules: Fallback rules without hostname
Precedence (Gateway API spec)¶
- Longest hostname (exact before wildcard)
- Longest path match
- Method present
- Most header matches
- Most query parameter matches
Config Push¶
The controller pushes routing config via HTTP:
Controller ──PUT /config──▶ Proxy Config API
│
compile routing table
│
atomic.Pointer.Store()
│
lock-free reads ◀── request goroutines
Config versioning prevents stale updates. Each push includes a monotonically increasing version number; the proxy rejects versions older than current.
Filters¶
| Filter | Phase | Behavior |
|---|---|---|
| RequestHeaderModifier | Request | Add/set/remove request headers |
| ResponseHeaderModifier | Response | Add/set/remove response headers |
| RequestRedirect | Request | Return redirect response (short-circuit) |
| URLRewrite | Request | Modify URL path and/or host |
| RequestMirror | Request | Clone request to mirror backend (async) |
Backend Selection¶
Weighted random selection using cumulative weight sums:
- Precompute cumulative weights:
[30, 30+70] = [30, 100] - Generate random number in
[0, totalWeight) - Linear scan in cumulative weight array
- Each backend has its own
*http.Transportwith connection pooling
Tunnel Integration¶
GatewayOriginProxy implements connection.OriginProxy:
ProxyHTTP: Delegates toproxy.Handler.ServeHTTPProxyTCP: Returns error (TCPRoute is future work)
StartTunnel builds the full cloudflared supervisor config:
- Parse tunnel token (base64 JSON)
- Build edge TLS configs (Cloudflare root CAs + system pool)
- Create protocol selector (auto: QUIC preferred)
- In-process mode (default): Set
OverrideProxyon supervisor config to route all requests directly toproxy.Handler, bypassing ingress rules entirely - Standalone mode: Build catch-all ingress to
http://localhost:PROXY_PORTso cloudflared forwards traffic to the local proxy HTTP server - Start
supervisor.StartTunnelDaemon