HTTPRoute¶
HTTPRoute is the primary resource for configuring HTTP routing through Cloudflare Tunnel.
Feature Support¶
| Feature | Supported | Notes |
|---|---|---|
| Hostname matching | ✅ | Wildcard * supported |
| Path matching (Prefix, Exact) | ✅ | |
| Path matching (RegularExpression) | ✅ | Requires L7 proxy |
| Header matching | ✅ | Requires L7 proxy |
| Query parameter matching | ✅ | Requires L7 proxy |
| HTTP method matching | ✅ | Requires L7 proxy |
| Backend weight selection (highest wins) | ✅ | |
| Weighted traffic splitting | ✅ | Requires L7 proxy |
| RequestHeaderModifier filter | ✅ | Requires L7 proxy |
| ResponseHeaderModifier filter | ✅ | Requires L7 proxy |
| RequestRedirect filter | ✅ | Requires L7 proxy |
| URLRewrite filter | ✅ | Requires L7 proxy |
| RequestMirror filter | ✅ | Requires L7 proxy |
| Per-route timeouts | ✅ | Requires L7 proxy |
| Cross-namespace routing | ✅ | Via ReferenceGrant |
| ExternalName service backends | ✅ | |
| GRPCRoute | ✅ |
L7 proxy requirement
Header matching, query parameter matching, method matching, traffic splitting, and filters require the L7 proxy to be enabled. See the L7 Proxy Guide for setup instructions.
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 | Requires L7 proxy |
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, the backend with the highest weight is selected:
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:
# Backend with highest weight is selected
- name: primary-service
port: 80
weight: 80
- name: fallback-service
port: 80
weight: 20
# primary-service is selected (weight 80 > 20)
L7 proxy enables traffic splitting
Without the L7 proxy, the backend with the highest weight receives 100% of traffic. With the L7 proxy enabled, weights are used for true percentage-based traffic splitting across backends.
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 active and synced to Cloudflare |
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.