> ## Documentation Index
> Fetch the complete documentation index at: https://ngrok.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Controlling Traffic Flow with Request Routing

> Configure request routing in Kubernetes to direct incoming traffic to the appropriate backend services based on rules.

Request routing is the core capability of an API Gateway, enabling it to direct incoming traffic to the appropriate backend service.
By defining routing rules, you can control how requests are handled, which services they reach, and under what conditions.

Proper request routing ensures:

🚀 Optimized performance by directing traffic efficiently. <br />
🔄 Seamless service rollouts by routing requests based on versioning, headers, or user location. <br />
🛡 Enhanced reliability with failover and fallback mechanisms. <br />

## 🔍 What are the benefits of request routing?

Modern applications often consist of multiple microservices that serve different functions.
A well-configured API Gateway can intelligently route traffic based on:

* Path-based rules (/api/v1/orders → Order Service, /api/v1/users → User Service).
* Header-based conditions (User-Agent: Mobile → Mobile Backend, User-Agent: Desktop → Web Backend).
* Query parameters & cookies (A/B testing, canary deployments).

Key Benefits:

* **Efficiently Direct Requests:** Ensure each request reaches the correct service, region, or version.
* **Enable Canary & Blue-Green Deployments:** Route a subset of traffic to new versions before full rollout.
* **Improve Scalability:** Load balance requests across multiple backend instances.
* **Enhance Security & Compliance:** Route traffic based on user identity, location, or authentication level.
* **Optimize Multi-Region Deployments:** Direct users to the nearest geographically distributed service.

## Using CloudEndpoints with AgentEndpoints

`AgentEndpoint` resources allow you to configure an upstream that should receive the traffic sent to the `AgentEndpoint`, but you can only specify a single upstream.
`CloudEndpoint` resources do not have configuration for an upstream, but you can use Traffic Policy configuration with the [forward-internal](/traffic-policy/actions/forward-internal/) action to forward to other endpoints.

The most common pattern is to create an internal `AgentEndpoint` for your upstream services. An internal endpoint is used so that your upstream service is not directly accessible to the public internet, but other ngrok endpoints can route to it using the `forward-internal` action.
Then, a `CloudEndpoint` resource is created for the hostname that you would like to use. The `CloudEndpoint` is then given Traffic Policy configuration to forward to your `AgentEndpoints`.
This makes it simple to have a central resource for a given hostname that defines Traffic Policy actions for things like rate-limiting and authentication that you may like to enforce for the entire hostname while having all of the routing rules for the hostname located in the same location.

The following example showcases how you can create two different internal `AgentEndpoint` resources for two different upstream services, and then use a `CloudEndpoint` to accept traffic for an example hostname and route to the desired `AgentEndpoint`.

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: AgentEndpoint
metadata:
  name: foo-service
  namespace: default
spec:
  url: http://foo-service.internal:80
  upstream:
    url: http://foo-service.example-namespace:8080
  bindings:
  - internal
```

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: AgentEndpoint
metadata:
  name: bar-service
  namespace: default
spec:
  url: http://bar-service.internal:80
  upstream:
    url: http://bar-service.example-namespace:8080
  bindings:
  - internal
```

```yaml theme={null}
apiVersion: ngrok.k8s.ngrok.com/v1alpha1
kind: CloudEndpoint
metadata:
  name: example-cloud-endpoint
spec:
  url: https://example-hostname.ngrok.io
  bindings:
  - public
  trafficPolicy:
    policy:
      on_http_request:
      - expressions:
        - "req.url.path.startsWith('/foo-service')"
        actions:
        - type: forward-internal
          config:
            url: http://foo-service.internal:80
      - expressions:
        - "req.url.path.startsWith('/bar-service')"
        actions:
        - type: forward-internal
          config:
            url: http://bar-service.internal:80
```

`CloudEndpoint` and `AgentEndpoint` resources offer a lot of flexibility in determining when to run Traffic Policy actions.
Check out the [Traffic Policy expressions](/traffic-policy/how-it-works#expressions) page for more information about the expressions you can write.

<Tip>
  You can also include Traffic Policy configuration on your internal AgentEndpoint resources that will run after the CloudEndpoint forwards the request to them
</Tip>

## Exact path matching

The following examples showcase how you can match on an exact path.
The request will not be routed unless it has the exact path `/example`, so `/example/foo` will not be routed.

<Tabs>
  <Tab title="CloudEndpoint with AgentEndpoint">
    ### 1. Create an `AgentEndpoint` for your upstream `Service`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: AgentEndpoint
    metadata:
      name: example-service
      namespace: default
    spec:
      url: http://example-service.internal:80
      upstream:
        url: http://example-service.example-namespace:8080
      bindings:
      - internal
    ```

    ### 2. Create a `CloudEndpoint` that routes to the `AgentEndpoint`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: CloudEndpoint
    metadata:
      name: example-cloud-endpoint
    spec:
      url: https://example-hostname.ngrok.io
      bindings:
      - public
      trafficPolicy:
        policy:
          on_http_request:
          - expressions:
            - "req.url.path == '/example'"
            actions:
            - type: forward-internal
              config:
                url: http://example-service.internal:80
    ```
  </Tab>

  <Tab title="Ingress">
    ```yaml theme={null}
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
      namespace: default
    spec:
      ingressClassName: ngrok
      rules:
        - host: example-hostname.ngrok.io
          http:
            paths:
              - path: /example
                pathType: Exact
                backend:
                  service:
                    name: example-service
                    port:
                      number: 80
    ```
  </Tab>

  <Tab title="Gateway API">
    Check out the [Gateway API HTTPRoute matching docs](https://gateway-api.sigs.k8s.io/api-types/httproute/#matches) for more information on matching requests.

    ### 1. Create a `Gateway`

    If you already have a `Gateway` you can use that instead

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: example-gateway
      namespace: default
    spec:
      gatewayClassName: ngrok
      listeners:
        - name: example
          hostname: "example-hostname.ngrok.io"
          port: 443
          protocol: HTTPS
    ```

    ### 2. Create an `HTTPRoute` with Exact Path Matching

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: example-route
      namespace: default
    spec:
      hostnames:
      - example-hostname.ngrok.io
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: example-gateway
        namespace: default
      rules:
      - matches:
        - path:
            type: Exact
            value: /example
        backendRefs:
          - group: ""
            kind: Service
            name: example-service
            port: 80
            weight: 1
    ```
  </Tab>
</Tabs>

## Path prefix matching

The following examples showcase how you can match using a path prefix.
Any request that has a path starting with `/example` will be routed, so `/example/foo` will be routed as well.

<Tabs>
  <Tab title="CloudEndpoint with AgentEndpoint">
    ### 1. Create an `AgentEndpoint` for your upstream `Service`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: AgentEndpoint
    metadata:
      name: example-service
      namespace: default
    spec:
      url: http://example-service.internal:80
      upstream:
        url: http://example-service.example-namespace:8080
      bindings:
      - internal
    ```

    ### 2. Create a `CloudEndpoint` that routes to the `AgentEndpoint`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: CloudEndpoint
    metadata:
      name: example-cloud-endpoint
    spec:
      url: https://example-hostname.ngrok.io
      bindings:
      - public
      trafficPolicy:
        policy:
          on_http_request:
          - expressions:
            - "req.url.path.startsWith('/example')"
            actions:
            - type: forward-internal
              config:
                url: http://example-service.internal:80
    ```
  </Tab>

  <Tab title="Ingress">
    ```yaml theme={null}
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
      namespace: default
    spec:
      ingressClassName: ngrok
      rules:
        - host: example-hostname.ngrok.io
          http:
            paths:
              - path: /example
                pathType: Prefix
                backend:
                  service:
                    name: example-service
                    port:
                      number: 80
    ```
  </Tab>

  <Tab title="Gateway API">
    Check out the [Gateway API HTTPRoute matching docs](https://gateway-api.sigs.k8s.io/api-types/httproute/#matches) for more information on matching requests.

    ### 1. Create a `Gateway`

    If you already have a `Gateway` you can use that instead

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: example-gateway
      namespace: default
    spec:
      gatewayClassName: ngrok
      listeners:
        - name: example
          hostname: "example-hostname.ngrok.io"
          port: 443
          protocol: HTTPS
    ```

    ### 2. Create an `HTTPRoute` with Prefix Path Matching

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: example-route
      namespace: default
    spec:
      hostnames:
      - example-hostname.ngrok.io
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: example-gateway
        namespace: default
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /example
        backendRefs:
          - group: ""
            kind: Service
            name: example-service
            port: 80
            weight: 1
    ```
  </Tab>
</Tabs>

## Request method matching

The following examples showcase how to create an endpoint that only routes requests with the `POST` method.

<Tabs>
  <Tab title="CloudEndpoint with AgentEndpoint">
    ### 1. Create an `AgentEndpoint` for your upstream `Service`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: AgentEndpoint
    metadata:
      name: example-service
      namespace: default
    spec:
      url: http://example-service.internal:80
      upstream:
        url: http://example-service.example-namespace:8080
      bindings:
      - internal
    ```

    ### 2. Create a `CloudEndpoint` that routes to the `AgentEndpoint`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: CloudEndpoint
    metadata:
      name: example-cloud-endpoint
    spec:
      url: https://example-hostname.ngrok.io
      bindings:
      - public
      trafficPolicy:
        policy:
          on_http_request:
          - expressions:
            - "req.method == 'POST'"
            actions:
            - type: forward-internal
              config:
                url: http://example-service.internal:80
    ```
  </Tab>

  <Tab title="Ingress">
    ❌ `Ingress` resources do not natively support request method matching, so this option requires using Gateway API or the `CloudEndpoint`/`AgentEndpoint` resources directly.
  </Tab>

  <Tab title="Gateway API">
    Check out the [Gateway API HTTPRoute matching docs](https://gateway-api.sigs.k8s.io/api-types/httproute/#matches) for more information on matching requests.

    ### 1. Create a `Gateway`

    If you already have a `Gateway` you can use that instead

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: example-gateway
      namespace: default
    spec:
      gatewayClassName: ngrok
      listeners:
        - name: example
          hostname: "example-hostname.ngrok.io"
          port: 443
          protocol: HTTPS
    ```

    ### 2. Create an `HTTPRoute` with Request Method Matching

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: example-route
      namespace: default
    spec:
      hostnames:
      - example-hostname.ngrok.io
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: example-gateway
        namespace: default
      rules:
      - matches:
        - method: "POST"
        backendRefs:
          - group: ""
            kind: Service
            name: example-service
            port: 80
            weight: 1
    ```
  </Tab>
</Tabs>

## Exact header matching

The following examples showcase how to create an endpoint that only routes requests if the header `x-request-header` is present with value `foo`.

<Tabs>
  <Tab title="CloudEndpoint with AgentEndpoint">
    ### 1. Create an `AgentEndpoint` for your upstream `Service`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: AgentEndpoint
    metadata:
      name: example-service
      namespace: default
    spec:
      url: http://example-service.internal:80
      upstream:
        url: http://example-service.example-namespace:8080
      bindings:
      - internal
    ```

    ### 2. Create a `CloudEndpoint` that routes to the `AgentEndpoint`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: CloudEndpoint
    metadata:
      name: example-cloud-endpoint
    spec:
      url: https://example-hostname.ngrok.io
      bindings:
      - public
      trafficPolicy:
        policy:
          on_http_request:
          - expressions:
            - "req.url.path.startsWith('/')"

            - "req.headers.exists_one(x, x == 'x-request-header') && req.headers['x-request-header'].join(',') == 'foo'"
            actions:
            - type: forward-internal
              config:
                url: http://example-service.internal:80
    ```
  </Tab>

  <Tab title="Ingress">
    ❌ `Ingress` resources do not natively support header matching, so this option requires using Gateway API or the `CloudEndpoint`/`AgentEndpoint` resources directly.
  </Tab>

  <Tab title="Gateway API">
    Check out the [Gateway API HTTPRoute matching docs](https://gateway-api.sigs.k8s.io/api-types/httproute/#matches) for more information on matching requests.

    ### 1. Create a `Gateway`

    If you already have a `Gateway` you can use that instead

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: example-gateway
      namespace: default
    spec:
      gatewayClassName: ngrok
      listeners:
        - name: example
          hostname: "example-hostname.ngrok.io"
          port: 443
          protocol: HTTPS
    ```

    ### 2. Create an `HTTPRoute` with Exact Header Matching

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: example-route
      namespace: default
    spec:
      hostnames:
      - example-hostname.ngrok.io
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: example-gateway
        namespace: default
      rules:
      - matches:
        - headers:
          - type: Exact
            name: x-request-header
            value: foo
        backendRefs:
          - group: ""
            kind: Service
            name: example-service
            port: 80
            weight: 1
    ```
  </Tab>
</Tabs>

## Regex header matching

The following examples showcase how to create an endpoint that only routes requests if the header `x-request-header` is present and the value matches the regex `x-value-.*`

<Tabs>
  <Tab title="CloudEndpoint with AgentEndpoint">
    ### 1. Create an `AgentEndpoint` for your upstream `Service`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: AgentEndpoint
    metadata:
      name: example-service
      namespace: default
    spec:
      url: http://example-service.internal:80
      upstream:
        url: http://example-service.example-namespace:8080
      bindings:
      - internal
    ```

    ### 2. Create a `CloudEndpoint` that routes to the `AgentEndpoint`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: CloudEndpoint
    metadata:
      name: example-cloud-endpoint
    spec:
      url: https://example-hostname.ngrok.io
      bindings:
      - public
      trafficPolicy:
        policy:
          on_http_request:
          - expressions:
            - "req.headers.exists_one(x, x == 'x-request-header') && req.headers['x-request-header'].join(',').matches('x-value-.*')"
            actions:
            - type: forward-internal
              config:
                url: http://example-service.internal:80
    ```
  </Tab>

  <Tab title="Ingress">
    ❌ `Ingress` resources do not natively support header matching, so this option requires using Gateway API or the `CloudEndpoint`/`AgentEndpoint` resources directly.
  </Tab>

  <Tab title="Gateway API">
    Check out the [Gateway API HTTPRoute matching docs](https://gateway-api.sigs.k8s.io/api-types/httproute/#matches) for more information on matching requests.

    ### 1. Create a `Gateway`

    If you already have a `Gateway` you can use that instead

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: example-gateway
      namespace: default
    spec:
      gatewayClassName: ngrok
      listeners:
        - name: example
          hostname: "example-hostname.ngrok.io"
          port: 443
          protocol: HTTPS
    ```

    ### 2. Create an `HTTPRoute` with Regex Header Matching

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: example-route
      namespace: default
    spec:
      hostnames:
      - example-hostname.ngrok.io
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: example-gateway
        namespace: default
      rules:
      - matches:
        - headers:
          - type: RegularExpression
            name: x-request-header
            value: x-value-.*
        backendRefs:
          - group: ""
            kind: Service
            name: example-service
            port: 80
            weight: 1
    ```
  </Tab>
</Tabs>

## Exact query parameter matching

The following examples showcase how to create an endpoint that only routes requests if the query parameter `my-query-param` is present with value `foo`.

<Tabs>
  <Tab title="CloudEndpoint with AgentEndpoint">
    ### 1. Create an `AgentEndpoint` for your upstream `Service`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: AgentEndpoint
    metadata:
      name: example-service
      namespace: default
    spec:
      url: http://example-service.internal:80
      upstream:
        url: http://example-service.example-namespace:8080
      bindings:
      - internal
    ```

    ### 2. Create a `CloudEndpoint` that routes to the `AgentEndpoint`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: CloudEndpoint
    metadata:
      name: example-cloud-endpoint
    spec:
      url: https://example-hostname.ngrok.io
      bindings:
      - public
      trafficPolicy:
        policy:
          on_http_request:
          - expressions:
            - "req.url.query_params.exists_one(x, x == 'my-query-param') && req.url.query_params['my-query-param'].join(',') == 'foo'"
            actions:
            - type: forward-internal
              config:
                url: http://example-service.internal:80
    ```
  </Tab>

  <Tab title="Ingress">
    ❌ `Ingress` resources do not natively support header matching, so this option requires using Gateway API or the `CloudEndpoint`/`AgentEndpoint` resources directly.
  </Tab>

  <Tab title="Gateway API">
    Check out the [Gateway API HTTPRoute matching docs](https://gateway-api.sigs.k8s.io/api-types/httproute/#matches) for more information on matching requests.

    ### 1. Create a `Gateway`

    If you already have a `Gateway` you can use that instead

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: example-gateway
      namespace: default
    spec:
      gatewayClassName: ngrok
      listeners:
        - name: example
          hostname: "example-hostname.ngrok.io"
          port: 443
          protocol: HTTPS
    ```

    ### 2. Create an `HTTPRoute` with Exact Query Parameter Matching

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: example-route
      namespace: default
    spec:
      hostnames:
      - example-hostname.ngrok.io
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: example-gateway
        namespace: default
      rules:
      - matches:
        - queryParams:
          - type: Exact
            name: my-query-param
            value: foo
        backendRefs:
          - group: ""
            kind: Service
            name: example-service
            port: 80
            weight: 1
    ```
  </Tab>
</Tabs>

## Regex query parameter matching

The following examples showcase how to create an endpoint that only routes requests if the query parameter `my-query-param` is present and its value matches the regex `value-.*`.

<Tabs>
  <Tab title="CloudEndpoint with AgentEndpoint">
    ### 1. Create an `AgentEndpoint` for your upstream `Service`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: AgentEndpoint
    metadata:
      name: example-service
      namespace: default
    spec:
      url: http://example-service.internal:80
      upstream:
        url: http://example-service.example-namespace:8080
      bindings:
      - internal
    ```

    ### 2. Create a `CloudEndpoint` that routes to the `AgentEndpoint`

    ```yaml theme={null}
    apiVersion: ngrok.k8s.ngrok.com/v1alpha1
    kind: CloudEndpoint
    metadata:
      name: example-cloud-endpoint
    spec:
      url: https://example-hostname.ngrok.io
      bindings:
      - public
      trafficPolicy:
        policy:
          on_http_request:
          - expressions:
            - "req.url.query_params.exists_one(x, x == 'my-query-param') && req.url.query_params['my-query-param'].join(',').matches('value-.*')"
            actions:
            - type: forward-internal
              config:
                url: http://example-service.internal:80
    ```
  </Tab>

  <Tab title="Ingress">
    ❌ `Ingress` resources do not natively support query parameter matching, so this option requires using Gateway API or the `CloudEndpoint`/`AgentEndpoint` resources directly.
  </Tab>

  <Tab title="Gateway API">
    Check out the [Gateway API HTTPRoute matching docs](https://gateway-api.sigs.k8s.io/api-types/httproute/#matches) for more information on matching requests.

    ### 1. Create a `Gateway`

    If you already have a `Gateway` you can use that instead

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: example-gateway
      namespace: default
    spec:
      gatewayClassName: ngrok
      listeners:
        - name: example
          hostname: "example-hostname.ngrok.io"
          port: 443
          protocol: HTTPS
    ```

    ### 2. Create an `HTTPRoute` with Regex Query Parameter Matching

    ```yaml theme={null}
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: example-route
      namespace: default
    spec:
      hostnames:
      - example-hostname.ngrok.io
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: example-gateway
        namespace: default
      rules:
      - matches:
        - queryParams:
          - type: RegularExpression
            name: my-query-param
            value: value-.*
        backendRefs:
          - group: ""
            kind: Service
            name: example-service
            port: 80
            weight: 1
    ```
  </Tab>
</Tabs>
