L7 Proxy Setup¶
The L7 proxy runs cloudflared tunnel transport with a built-in reverse proxy that implements full Gateway API HTTPRoute routing in-process, removing the limitations of the Cloudflare Tunnel ingress API.
Architecture¶
flowchart TB
subgraph Internet
USER[Client]
end
subgraph Cloudflare["Cloudflare Edge"]
EDGE[Edge Network]
end
subgraph Kubernetes["Kubernetes Cluster"]
subgraph Controller["Control Plane"]
CTRL[Controller]
end
subgraph Proxy["Data Plane (N replicas)"]
CFD[cloudflared transport]
L7[L7 Reverse Proxy]
CAPI[Config API]
end
SVC[Backend Services]
HR[HTTPRoute]
GW[Gateway]
end
USER -->|HTTPS| EDGE
EDGE -->|QUIC tunnel| CFD
CFD --> L7
L7 -->|route| SVC
HR -->|watch| CTRL
GW -->|watch| CTRL
CTRL -->|PUT /config| CAPI
CAPI -->|atomic swap| L7 Prerequisites¶
- Kubernetes 1.25+
- Gateway API CRDs installed
- Cloudflare Tunnel created with a valid token
- Helm 3.x
Installation¶
1. Create tunnel token Secret¶
kubectl create secret generic tunnel-token \
--from-literal=tunnel-token=YOUR_BASE64_TUNNEL_TOKEN \
--namespace cloudflare-tunnel-system
2. Enable proxy in Helm values¶
3. Install or upgrade¶
helm upgrade --install cloudflare-tunnel \
oci://ghcr.io/lexfrei/charts/cloudflare-tunnel-gateway-controller \
--namespace cloudflare-tunnel-system \
--create-namespace \
--values values.yaml
Features Enabled by L7 Proxy¶
The L7 proxy enables the following Gateway API features that are not available with only the Cloudflare Tunnel API:
- Exact path matching
- Header matching
- Query parameter matching
- HTTP method matching
- Request header modification
- Response header modification
- URL rewriting
- Request redirect
- Request mirroring
- Weighted traffic splitting
- Regex path matching
- Per-route timeouts
Configuration¶
The controller automatically discovers proxy pod endpoints via the headless Service and pushes routing configuration whenever HTTPRoute resources change.
Environment Variables¶
The proxy binary accepts the following environment variables:
| Variable | Default | Description |
|---|---|---|
TUNNEL_TOKEN | Required for tunnel mode; omit for standalone/dev mode | Cloudflare tunnel token (base64) |
PROXY_CONFIG_ADDR | :8081 | Config API listen address |
PROXY_ADDR | :8080 | Proxy listen address |
PROXY_AUTH_TOKEN | "" (empty, no auth) | Bearer token for config push API authentication. If unset, the API is unauthenticated. |
Health Endpoints¶
| Endpoint | Port | Description |
|---|---|---|
/healthz | Config API | Liveness check |
/readyz | Config API | Readiness (config loaded at least once) |
Example HTTPRoute¶
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: advanced-routing
spec:
parentRefs:
- name: cloudflare-tunnel
hostnames:
- app.example.com
rules:
- matches:
- path:
type: Exact
value: /api/v2/health
headers:
- name: X-API-Version
value: "2"
method: GET
filters:
- type: ResponseHeaderModifier
responseHeaderModifier:
add:
- name: X-Proxy
value: cloudflare-tunnel-gateway
backendRefs:
- name: api-v2
port: 8080
weight: 80
- name: api-v2-canary
port: 8080
weight: 20
Monitoring¶
The proxy exposes Prometheus metrics on the config API port. Enable the ServiceMonitor to scrape them automatically:
Troubleshooting¶
Proxy pods not becoming ready¶
Check that the tunnel token is valid:
Routes not updating¶
Verify the controller can reach the proxy config API:
kubectl get endpoints --selector app.kubernetes.io/component=proxy \
--namespace cloudflare-tunnel-system
Config API returns stale version¶
The controller pushes config atomically. Check controller logs for push errors: