HTTPRoute¶
HTTPRoute is the primary resource for configuring HTTP routing through Cloudflare Tunnel.
Feature Support¶
All matching and filter behavior is performed by the in-process L7 proxy that the chart deploys alongside the controller.
| Feature | Supported | Notes |
|---|---|---|
| Hostname matching | ✅ | Wildcard * supported |
| Path matching (Prefix, Exact, RegularExpression) | ✅ | RE2 syntax for regex |
| Header matching | ✅ | Exact and RegularExpression |
| Query parameter matching | ✅ | Exact and RegularExpression |
| HTTP method matching | ✅ | All HTTP methods |
| Weighted traffic splitting | ✅ | True traffic distribution across backends |
| RequestHeaderModifier filter | ✅ | |
| ResponseHeaderModifier filter | ✅ | |
| RequestRedirect filter | ✅ | |
| URLRewrite filter | ✅ | |
| RequestMirror filter | ✅ | |
| Per-route timeouts | ✅ | |
| Cross-namespace routing | ✅ | Via ReferenceGrant |
| ExternalName service backends | ✅ |
Basic Example¶
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app
namespace: default
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- app.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-service
port: 80
Path-Based Routing¶
Route different paths to different services:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-routes
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- api.example.com
rules:
# Exact match takes priority
- matches:
- path:
type: Exact
value: /health
backendRefs:
- name: health-service
port: 8080
# Prefix match for API v1
- matches:
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: api-v1
port: 8080
# Prefix match for API v2
- matches:
- path:
type: PathPrefix
value: /v2
backendRefs:
- name: api-v2
port: 8080
Path Match Types¶
| Type | Description | Notes |
|---|---|---|
PathPrefix | Matches paths starting with value | |
Exact | Matches exact path only | |
RegularExpression | Matches path against regex pattern (RE2) |
Multiple Hostnames¶
Route multiple hostnames to the same service:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: multi-host
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- app.example.com
- www.example.com
- "*.staging.example.com"
rules:
- backendRefs:
- name: web-app
port: 80
Wildcard SSL
Multi-level subdomains like *.staging.example.com require Advanced Certificate Manager for SSL certificates.
Backend Selection with Weights¶
When multiple backends are specified, traffic is split across them in proportion to their weights:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: weighted-backend
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- app.example.com
rules:
- backendRefs:
# Traffic is split proportionally by weight
- name: primary-service
port: 80
weight: 80
- name: fallback-service
port: 80
weight: 20
# ~80% to primary-service, ~20% to fallback-service
Traffic splitting
Weights are used for true percentage-based traffic splitting across backends — the in-process L7 proxy performs the selection at request time.
Cross-Namespace Routing¶
Route to services in different namespaces using ReferenceGrant:
---
# ReferenceGrant in target namespace
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-app-to-backend
namespace: backend-namespace
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-namespace
to:
- group: ""
kind: Service
---
# HTTPRoute in source namespace
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: cross-ns-route
namespace: app-namespace
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- myapp.example.com
rules:
- backendRefs:
- name: backend-service
namespace: backend-namespace
port: 8080
See ReferenceGrant for more details.
ExternalName Service Backends¶
Route traffic to external services using Kubernetes ExternalName Services:
---
# ExternalName Service pointing to external API
apiVersion: v1
kind: Service
metadata:
name: external-api
namespace: default
spec:
type: ExternalName
externalName: api.external.com
---
# HTTPRoute using ExternalName Service
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: external-route
namespace: default
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- myapp.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /external
backendRefs:
- name: external-api
port: 443
The controller resolves ExternalName Services and routes traffic directly to the external hostname (api.external.com:443 in this example).
Port and Scheme
The scheme (http or https) is determined by the port: port 443 uses HTTPS, all other ports use HTTP.
External-DNS Integration¶
Add annotations for automatic DNS record creation:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: with-dns
annotations:
external-dns.alpha.kubernetes.io/cloudflare-proxied: "true"
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- auto-dns.example.com
rules:
- backendRefs:
- name: my-service
port: 80
See External-DNS Integration for setup.
Listener Section Matching¶
Target specific Gateway listeners using sectionName:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: specific-listener
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
sectionName: http # Match listener name
hostnames:
- app.example.com
rules:
- backendRefs:
- name: my-service
port: 80
Checking Route Status¶
Verify that the route is accepted:
Expected output includes "type":"Accepted","status":"True".
Common Status Conditions¶
| Condition | Meaning |
|---|---|
Accepted: True | Route is accepted and programmed in the in-process proxy; Cloudflare Tunnel config updated (L7 routing happens in-cluster, not at the Cloudflare edge) |
Accepted: False | Route was rejected (check reason) |
ResolvedRefs: True | All backend references resolved |
ResolvedRefs: False | Backend reference failed (missing service or ReferenceGrant) |
Troubleshooting¶
Route Not Accepted¶
Check controller logs:
kubectl logs --selector app.kubernetes.io/name=cloudflare-tunnel-gateway-controller \
--namespace cloudflare-tunnel-system
Common causes:
- Gateway not found (wrong name or namespace in parentRefs)
- Cloudflare API error (invalid credentials)
- Service not found
Cross-Namespace Reference Denied¶
Ensure ReferenceGrant exists in the target namespace and allows your route's namespace.