Skip to content

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:

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 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.

kubectl get referencegrant --namespace backend-namespace