Skip to content

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:

kubectl get httproute my-app --output jsonpath='{.status.parents[*].conditions}'

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.

kubectl get referencegrant --namespace backend-namespace