Routes

Define HTTPRoutes for HAProxy Unified Gateway

The Gateway API defines specialized resources for routing different types of network traffic. You would use an HTTPRoute resource to route HTTP traffic. HTTPRoutes use routing rules to define how incoming HTTP requests should be forwarded to backend applications based on attributes such as hostname and/or URL path.

Prerequisites checklist Jump to heading

Before continuing, ensure that you’ve met these prerequisites:

  • Define a Gateway. When defining a Gateway, add an HTTP and/or HTTPS listener that sets its allowedRoutes property to accept routes of kind HTTPRoute.

Define routing rules Jump to heading

In your HTTPRoutes, you’ll define rules for routing HTTP requests to your backend applications. These rules include match conditions for hostnames and/or URL paths. Hostname-based routing is useful when you want to route traffic based on the domain. For example, you want to route traffic for api.example.com and web.example.com to different services. Path-based routing is useful when you have multiple applications under the same domain and want to route traffic based on the URL path. For example, you want to route traffic for example.com/web.

Tip

You can combine hostname-based routing rules and path-based routing rules.

Implement hostname-based routing Jump to heading

You can configure hostname matching in three ways:

Match type Match behavior
No hostname Matches all hostnames accepted by the Gateway.
Exact hostname Matches only this domain. Requests to other domains or subdomains are filtered out. Example: web.example.com matches requests only to that subdomain.
Wildcard hostname Matches all subdomains. Example: *.example.com. This doesn’t match requests to the root domain; add an additional entry to hostnames in the HTTPRoute if you want to include the root domain.

The following steps show how to specify the hostname(s) at which the HTTPRoute will accept traffic for forwarding:

  1. For exact hostname and wildcard hostname matching: If your Gateway resource sets a hostname field, update it and omit or comment out hostname. This ensures that the Gateway will relay traffic for all of your domains. You’ll filter by hostname in the HTTPRoute resource.

    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    # hostname: "example.com"
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    # hostname: "example.com"
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f gateway.yaml
    nix
    kubectl apply -f gateway.yaml
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway configured
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway configured
  3. Define an HTTPRoute resource for your target domain(s). In this example, we route traffic for the hostname web.example.com.

    Section Description
    parentRefs References one or more Gateways to which an HTTPRoute tries to attach. This HTTPRoute will attach to Gateway resources that have listeners with allowedRoutes matching the HTTPRoute kind and a matching namespace. The sectionName field specifies the name of the listener on the Gateway to attach to. In this example, we attach to the HTTP listener, but you could attach to the HTTPS listener.
    hostnames Lists hostnames to accept traffic for. You can list multiple hostnames in this section. Alternatively, you can specify the wildcard *.example.com, for example, to match all subdomains. Omitting this field entirely indicates that you want to match all domains the Gateway accepts.
    rules Each entry has a backendRefs section to route to the specified service. For example, requests for web.example.com will route to web-svc. A backendRefs entry refers to the name of a Service resource and its listening port.
    web-hostname-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: web-hostname-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - web.example.com
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80
    web-hostname-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: web-hostname-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - web.example.com
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80
  4. Apply the changes with kubectl:

    nix
    kubectl apply -f web-hostname-route.yaml
    nix
    kubectl apply -f web-hostname-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/web-hostname-route created
    output
    text
    httproute.gateway.networking.k8s.io/web-hostname-route created
  5. If your HTTPRoute resource lists a backendRefs Service that’s in a namespace that’s different from the namespace where the HTTPRoute is defined, you’ll need to add a ReferenceGrant for cross-namespace service references.

Implement path-based routing Jump to heading

Migrating from Ingress API

Path-based routing with Gateway API behaves similarly to traditional Ingress rules. This makes it easy to migrate from HAProxy Kubernetes Ingress Controller or other Ingress controller implementations.

HTTPRoute supports three URL path matching strategies:

Match type Match behavior
Exact Matches only a single path. For example: /web; this doesn’t match /web/ or /web/v1.
PathPrefix Matches a path and all of its subpaths. For example: /web, /web/app.
RegularExpression Matches using a regular expression. For example: ^/web/.* to match any path beginning with /web/.

Tip

Use PathPrefix for most routing applications. Use Exact for single endpoints (such as /health) and RegularExpression only for advanced cases.

To implement path-based routing:

  1. Define an HTTPRoute for routing HTTP traffic for the target URL paths. In this example, we route traffic for the path /web.

    Section Description
    parentRefs References one or more Gateways to which an HTTPRoute tries to attach. This HTTPRoute will attach to Gateway resources that have listeners with allowedRoutes matching the HTTPRoute kind and a matching namespace. The sectionName field specifies the name of the listener on the Gateway to attach to. In this example, we attach to the HTTP listener, but you could attach to the HTTPS listener.
    rules Each entry has a matches and backendRefs section. In this example, we set the type of the path-matching rule to PathPrefix. This means that URL paths that begin with the specified value will be routed to the service specified by the backendRefs entry. For example, requests beginning with /web will route to web-svc. You can specify Exact to match only a single path specified by value, or specify RegularExpression and specify a regular expression in value for more complicated matching. A backendRefs entry refers to the name of a Service resource and its listening port.
    path-based-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: path-based-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    rules:
    - matches:
    - path:
    type: PathPrefix
    value: /web
    backendRefs:
    - name: web-svc
    namespace: default
    port: 80
    path-based-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: path-based-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    rules:
    - matches:
    - path:
    type: PathPrefix
    value: /web
    backendRefs:
    - name: web-svc
    namespace: default
    port: 80
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f path-based-route.yaml
    nix
    kubectl apply -f path-based-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/path-based-route created
    output
    text
    httproute.gateway.networking.k8s.io/path-based-route created
  3. Optional: If your HTTPRoute resource lists a backendRefs Service that’s in a namespace that’s different from the namespace where the HTTPRoute is defined, you’ll need to add a ReferenceGrant for cross-namespace service references.

  4. Optional: When using path-based routing, you may want to restrict which hostnames your Gateway will accept traffic for.

    • Update your Gateway resource to set the hostname field on the listener.

      gateway.yaml
      yaml
      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
      name: example-haproxy-gateway
      namespace: default
      spec:
      gatewayClassName: haproxy
      listeners:
      - name: http
      protocol: HTTP
      port: 31080
      hostname: "example.com"
      allowedRoutes:
      kinds:
      - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespaces:
      from: Same
      gateway.yaml
      yaml
      apiVersion: gateway.networking.k8s.io/v1
      kind: Gateway
      metadata:
      name: example-haproxy-gateway
      namespace: default
      spec:
      gatewayClassName: haproxy
      listeners:
      - name: http
      protocol: HTTP
      port: 31080
      hostname: "example.com"
      allowedRoutes:
      kinds:
      - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespaces:
      from: Same
    • Apply the changes with kubectl:

      nix
      kubectl apply -f gateway.yaml
      nix
      kubectl apply -f gateway.yaml
      output
      text
      gateway.gateway.networking.k8s.io/example-haproxy-gateway configured
      output
      text
      gateway.gateway.networking.k8s.io/example-haproxy-gateway configured
  5. Optional: To test connectivity with the Gateway and HTTPRoute you just defined, deploy the example application using Deployment and Service resources. The application uses the hashicorp/http-echo Docker container image. It’ll receive HTTP traffic on port 5678 and respond with text indicating the application’s name.

    Note that the Service is named web-svc, which is the same Service name you specified when you defined your HTTPRoute in the previous steps, and it listens on port 80. This is how the HTTPRoute knows the Service to route to.

    app.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: web-svc
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: web-svc
    template:
    metadata:
    labels:
    app: web-svc
    spec:
    containers:
    - name: web
    image: hashicorp/http-echo:0.2.3
    args: ["-text=WEB RESPONSE"]
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: web-svc
    namespace: default
    spec:
    selector:
    app: web-svc
    ports:
    - port: 80
    targetPort: 5678
    app.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: web-svc
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: web-svc
    template:
    metadata:
    labels:
    app: web-svc
    spec:
    containers:
    - name: web
    image: hashicorp/http-echo:0.2.3
    args: ["-text=WEB RESPONSE"]
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: web-svc
    namespace: default
    spec:
    selector:
    app: web-svc
    ports:
    - port: 80
    targetPort: 5678

    Apply the changes with kubectl:

    nix
    kubectl apply -f app.yaml
    nix
    kubectl apply -f app.yaml
    output
    text
    deployment.apps/web-svc created
    service/web-svc created
    output
    text
    deployment.apps/web-svc created
    service/web-svc created

Implement weighted traffic splitting Jump to heading

Use weighted traffic splitting when you want different percentages of traffic to route to different services. One use case is canary deployments. A canary deployment means routing a small percentage of traffic to the new version of your application, and then gradually ramping up, allowing you to release the new version in the safest possible way.

  1. Define an HTTPRoute for routing HTTP traffic to your service.

    Section Description
    parentRefs References one or more Gateways to which the HTTPRoute wants to attach, which in this case is example-haproxy-gateway. The sectionName field specifies the name of the listener on the Gateway to attach to.
    hostnames We’re using hostname-based routing, so we’re including the hostnames section. In this example, we attach to the HTTP listener, but you could attach to the HTTPS listener.
    rules Lists two services, blue and green. The blue service will receive 90% of the traffic and the green service will receive 10% of the traffic.
    canary-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: canary-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    rules:
    - backendRefs:
    - name: blue
    namespace: default
    port: 80
    weight: 9
    - name: green
    namespace: default
    port: 80
    weight: 1
    canary-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: canary-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    rules:
    - backendRefs:
    - name: blue
    namespace: default
    port: 80
    weight: 9
    - name: green
    namespace: default
    port: 80
    weight: 1
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f canary-route.yaml
    nix
    kubectl apply -f canary-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/canary-route created
    output
    text
    httproute.gateway.networking.k8s.io/canary-route created
  3. Optional: To test connectivity with the Gateway and HTTPRoute, deploy two test applications using Deployments and Services. Here, we define two example applications using the hashicorp/http-echo Docker container image. They will each receive HTTP traffic on port 5678 and respond with text indicating receipt of the request.

    Note that the Services are named blue and green, the same Service names you specified when you defined your HTTPRoute in the previous steps, both listening on port 80, which you defined in the HTTPRoute as well. This is how the HTTPRoute knows the Service to route to.

    apps.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: blue
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: blue
    template:
    metadata:
    labels:
    app: blue
    spec:
    containers:
    - name: blue
    image: hashicorp/http-echo
    args:
    - "-text=Hello from blue"
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: blue
    namespace: default
    spec:
    selector:
    app: blue
    ports:
    - port: 80
    targetPort: 5678
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: green
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: green
    template:
    metadata:
    labels:
    app: green
    spec:
    containers:
    - name: green
    image: hashicorp/http-echo
    args:
    - "-text=Hello from green"
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: green
    namespace: default
    spec:
    selector:
    app: green
    ports:
    - port: 80
    targetPort: 5678
    apps.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: blue
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: blue
    template:
    metadata:
    labels:
    app: blue
    spec:
    containers:
    - name: blue
    image: hashicorp/http-echo
    args:
    - "-text=Hello from blue"
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: blue
    namespace: default
    spec:
    selector:
    app: blue
    ports:
    - port: 80
    targetPort: 5678
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: green
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: green
    template:
    metadata:
    labels:
    app: green
    spec:
    containers:
    - name: green
    image: hashicorp/http-echo
    args:
    - "-text=Hello from green"
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: green
    namespace: default
    spec:
    selector:
    app: green
    ports:
    - port: 80
    targetPort: 5678
  4. Apply the changes with kubectl:

    nix
    kubectl apply -f apps.yaml
    nix
    kubectl apply -f apps.yaml
    output
    text
    deployment.apps/blue created
    service/blue created
    deployment.apps/green created
    service/green created
    output
    text
    deployment.apps/blue created
    service/blue created
    deployment.apps/green created
    service/green created

Enable CORS Jump to heading

Web browsers have a security feature that prevents unauthorized websites from accessing data belonging to other websites. It’s named the Same-origin policy and it restricts who can read or write data, based on the website’s domain name.

For example, if trusted-bank.com hosts a URL /account-details, it’s probable that requests to that URL should originate only from trusted-bank.com. If bad-guy.com secretly makes an asynchronous HTTP request to that URL in an attempt to retreive the account details of a person who is tricked into visiting bad-guy.com, the browser will stop bad-guy.com from reading the response. This protection is on by default. However, in some cases, you’ll want to permit other origins to access your data.

Several examples:

  • From one domain, such as www.trusted-bank.com, you want to use Javascript to make HTTP requests to a web API hosted at another domain, such as api.trusted-bank.com.
  • From your website, which is hosted at TCP port 80, you want to use Javascript to make HTTP requests to a web API hosted at a different port, such as 8080. The differences in port count as different origins.
  • You host a web API that you’d like to allow anyone to use to get data, without restrictions.

In cases like these, you’ll want to configure Cross-Origin Resource Sharing (CORS). With CORS, you can relax the Same-origin policy restrictions:

  • Add origins to an allowlist. They’ll be returned to the browser in an Access-Control-Allow-Origin header.
  • Name which HTTP methods are allowed, such as GET, POST, and DELETE, in response to a preflight request. These will be returned to the browser in an Access-Control-Allow-Methods header.
  • Name which request headers are allowed, which will be returned in an Access-Control-Allow-Headers header.
  • Name which headers the server can return in the response, which will be returned in an Access-Control-Expose-Headers header.
  • Set whether credentials can be included in the request. This will be returned in an Access-Control-Allow-Credentials header.
  • Set how long the results of a preflight request can be cached. This will be returned in an Access-Control-Max-Age header.

To configure CORS:

  1. Define an HTTPRoute for routing HTTP traffic to your service. Include a filter of type CORS, then include a cors section with the CORS properties. You can set allowOrigins, allowMethods, allowHeaders, and exposeHeaders each to a single asterisk (*), which allows all.

    cors-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: cors-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - api.example.com
    rules:
    - backendRefs:
    - name: api-service
    namespace: default
    port: 8080
    filters:
    - type: CORS
    cors:
    allowOrigins:
    - https://www.foo.com
    - https://www.bar.com
    - https://*.baz.com
    - http://fiz.com:8080
    allowMethods:
    - GET
    - DELETE
    - POST
    - PUT
    allowHeaders:
    - X-Request-Header1
    - X-Request-Header2
    exposeHeaders:
    - X-Response-Header3
    - X-Response-Header4
    allowCredentials: true
    maxAge: 3600
    cors-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: cors-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - api.example.com
    rules:
    - backendRefs:
    - name: api-service
    namespace: default
    port: 8080
    filters:
    - type: CORS
    cors:
    allowOrigins:
    - https://www.foo.com
    - https://www.bar.com
    - https://*.baz.com
    - http://fiz.com:8080
    allowMethods:
    - GET
    - DELETE
    - POST
    - PUT
    allowHeaders:
    - X-Request-Header1
    - X-Request-Header2
    exposeHeaders:
    - X-Response-Header3
    - X-Response-Header4
    allowCredentials: true
    maxAge: 3600
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f cors-route.yaml
    nix
    kubectl apply -f cors-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/cors-route created
    output
    text
    httproute.gateway.networking.k8s.io/cors-route created

Add a ReferenceGrant for cross-namespace service references Jump to heading

If your HTTPRoute lists a Service under backendRefs that’s in a different namespace than the HTTPRoute resource, you’ll need to define a ReferenceGrant resource to allow cross-namespace communication between the HTTPRoute and the Service.

Below, we allow an HTTPRoute in the default namespace to reference a Service in the foo namespace. Note that the to section doesn’t need a namespace because a ReferenceGrant can refer only to resources defined in its own namespace.

foo-referencegrant.yaml
yaml
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: ReferenceGrant
metadata:
name: refgrantns1
namespace: foo
spec:
from:
- group: "gateway.networking.k8s.io"
kind: "HTTPRoute"
namespace: default
to:
- group: ""
kind: "Service"
foo-referencegrant.yaml
yaml
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: ReferenceGrant
metadata:
name: refgrantns1
namespace: foo
spec:
from:
- group: "gateway.networking.k8s.io"
kind: "HTTPRoute"
namespace: default
to:
- group: ""
kind: "Service"

Apply the changes with kubectl:

nix
kubectl apply -f foo-referencegrant.yaml
nix
kubectl apply -f foo-referencegrant.yaml

Redirect to HTTPS Jump to heading

You can use a RequestRedirect filter to redirect a request from HTTP to HTTPS. You shouldn’t use this in combination with the URLRewrite filter.

To redirect requests from HTTP to HTTPS:

  1. Check that your gateway has HTTP and HTTPS listeners.

  2. Add two HTTPRoute resources:

    • The first uses a RequestRedirect filter to redirect HTTP requests to the HTTPS scheme. It also sets port to the nodePort where the gateway’s HTTPS listener is listening. In this case, that’s nodePort 31443.

    • The second HTTPRoute resource receives the HTTPS traffic and relays it to the backend application.

    redirect-to-https-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: redirect-to-https-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "payments.example.com"
    rules:
    - filters:
    - type: RequestRedirect
    requestRedirect:
    scheme: https
    port: 31443
    statusCode: 302
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: https-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: https-listener
    hostnames:
    - "payments.example.com"
    rules:
    - backendRefs:
    - name: payments-svc
    namespace: default
    port: 80
    redirect-to-https-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: redirect-to-https-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "payments.example.com"
    rules:
    - filters:
    - type: RequestRedirect
    requestRedirect:
    scheme: https
    port: 31443
    statusCode: 302
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: https-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: https-listener
    hostnames:
    - "payments.example.com"
    rules:
    - backendRefs:
    - name: payments-svc
    namespace: default
    port: 80
  3. Apply the changes with kubectl:

    nix
    kubectl apply -f redirect-to-https-route.yaml
    nix
    kubectl apply -f redirect-to-https-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/redirect-to-https-route created
    httproute.gateway.networking.k8s.io/https-route created
    output
    text
    httproute.gateway.networking.k8s.io/redirect-to-https-route created
    httproute.gateway.networking.k8s.io/https-route created

Redirect to a different hostname Jump to heading

You can use a RequestRedirect filter to redirect a request to a different DNS hostname. For example, you can redirect from example.com to www.example.com. You shouldn’t use this in combination with the URLRewrite filter.

To redirect requests to a different hostname:

  1. Add two HTTPRoute resources:

    • The first HTTPRoute resource matches the hostname example.com. It uses a RequestRedirect filter to redirect to the www.example.com hostname. It also sets port to the nodePort where the gateway’s HTTP listener is listening. In this case, that’s nodePort 31080.

    • The second HTTPRoute resource matches the hostname www.example.com. It receives the request and relays it to the backend application.

    redirect-hostname-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: hostname-redirect
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    rules:
    - filters:
    - type: RequestRedirect
    requestRedirect:
    scheme: http
    hostname: "www.example.com"
    port: 31080
    statusCode: 302
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: www-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "www.example.com"
    rules:
    - backendRefs:
    - name: www-svc
    namespace: default
    port: 80
    redirect-hostname-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: hostname-redirect
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    rules:
    - filters:
    - type: RequestRedirect
    requestRedirect:
    scheme: http
    hostname: "www.example.com"
    port: 31080
    statusCode: 302
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: www-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "www.example.com"
    rules:
    - backendRefs:
    - name: www-svc
    namespace: default
    port: 80
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f redirect-hostname-route.yaml
    nix
    kubectl apply -f redirect-hostname-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/hostname-redirect created
    httproute.gateway.networking.k8s.io/www-route created
    output
    text
    httproute.gateway.networking.k8s.io/hostname-redirect created
    httproute.gateway.networking.k8s.io/www-route created

Redirect to a different URL path Jump to heading

You can use a RequestRedirect filter to redirect a request to a different URL path. For example, suppose that you wanted to give a simple way for users to get to the latest documentation of your API. You could redirect from the path /api/latest to whichever version was the latest one, such as /api/v2. Then, later, to /api/v3 and so on.

To redirect requests to a different URL path:

  1. Add one HTTPRoute resource that has two rules.

    • The first rule matches URL paths prefixed with /api/latest. It uses a RequestRedirect filter to redirect the request to the URL path /api/v2. In this example, we’re using the filter type ReplacePrefixMatch, which replaces only the prefix in the URL path, preserving the rest of the URL path and arguments. You can also set type to ReplaceFullPath and set replaceFullPath to the URL path that will replace the entire path.

    • The second rule matches requests that have URL paths prefixed with /api/v2 and relays them to the backend application.

    redirect-path-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: redirect-path-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    - "www.example.com"
    rules:
    - matches:
    - path:
    type: PathPrefix
    value: /api/latest
    filters:
    - type: RequestRedirect
    requestRedirect:
    scheme: http
    path:
    type: ReplacePrefixMatch
    replacePrefixMatch: /api/v2
    port: 31080
    statusCode: 302
    - matches:
    - path:
    type: PathPrefix
    value: /api/v2
    backendRefs:
    - name: api-v2-svc
    namespace: default
    port: 80
    redirect-path-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: redirect-path-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    - "www.example.com"
    rules:
    - matches:
    - path:
    type: PathPrefix
    value: /api/latest
    filters:
    - type: RequestRedirect
    requestRedirect:
    scheme: http
    path:
    type: ReplacePrefixMatch
    replacePrefixMatch: /api/v2
    port: 31080
    statusCode: 302
    - matches:
    - path:
    type: PathPrefix
    value: /api/v2
    backendRefs:
    - name: api-v2-svc
    namespace: default
    port: 80
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f redirect-path-route.yaml
    nix
    kubectl apply -f redirect-path-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/redirect-path-route created
    output
    text
    httproute.gateway.networking.k8s.io/redirect-path-route created

Rewrite the requested URL path Jump to heading

You may want to rewrite the URL path before forwarding the request to the backend, because:

  • Your backend expects a specific URL structure.
  • You want to hide internal routing details.
  • You’re consolidating multiple backend services under a shared URL prefix.
  • You want to expose a simpler API.
  • You’re migrating legacy Ingress rules to Gateway API.

To rewrite the requested URL path:

  1. Define an HTTPRoute for routing HTTP traffic to your service.

    The path-matching rule specifies the type as PathPrefix. This means that for URL paths that begin with the specified value will be routed to the corresponding service specified by the backendRefs in the rule. There’s also a filter of type: URLRewrite that instructs the HTTPRoute to replace /service with /.

    rewrite-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: rewrite-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    rules:
    - matches:
    - path:
    type: PathPrefix
    value: /service
    filters:
    - type: URLRewrite
    urlRewrite:
    path:
    type: ReplacePrefixMatch
    replacePrefixMatch: /
    backendRefs:
    - name: rewrite-backend-svc
    namespace: default
    port: 80
    rewrite-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: rewrite-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    rules:
    - matches:
    - path:
    type: PathPrefix
    value: /service
    filters:
    - type: URLRewrite
    urlRewrite:
    path:
    type: ReplacePrefixMatch
    replacePrefixMatch: /
    backendRefs:
    - name: rewrite-backend-svc
    namespace: default
    port: 80
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f rewrite-route.yaml
    nix
    kubectl apply -f rewrite-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/rewrite-route created
    output
    text
    httproute.gateway.networking.k8s.io/rewrite-route created
  3. Optional: To test connectivity with the Gateway and HTTPRoute, deploy a test application using a Deployment and a Service. Here, we define an example application using the hashicorp/http-echo Docker container image. It will receive HTTP traffic on port 5678 (the Gateway terminates the TLS connection and then communicates with backend services over HTTP) and respond with text indicating receipt of the request.

    Note that the Service is named rewrite-backend-svc, the same Service name you specified when you defined your HTTPRoute in the previous steps, listening on port 80, which you defined in the HTTPRoute as well. This is how the HTTPRoute knows what Service to route to.

    apps.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: rewrite-backend
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: rewrite-backend
    template:
    metadata:
    labels:
    app: rewrite-backend
    spec:
    containers:
    - name: echo
    image: hashicorp/http-echo
    args:
    - "-text=Rewrite backend reached"
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: rewrite-backend-svc
    namespace: default
    spec:
    selector:
    app: rewrite-backend
    ports:
    - port: 80
    targetPort: 5678
    apps.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: rewrite-backend
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: rewrite-backend
    template:
    metadata:
    labels:
    app: rewrite-backend
    spec:
    containers:
    - name: echo
    image: hashicorp/http-echo
    args:
    - "-text=Rewrite backend reached"
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: rewrite-backend-svc
    namespace: default
    spec:
    selector:
    app: rewrite-backend
    ports:
    - port: 80
    targetPort: 5678
  4. Apply the changes with kubectl:

    nix
    kubectl apply -f apps.yaml
    nix
    kubectl apply -f apps.yaml
    output
    text
    deployment.apps/tls-test created
    service/tls-test-svc created
    output
    text
    deployment.apps/tls-test created
    service/tls-test-svc created

Modify response headers Jump to heading

You can modify the HTTP headers that your application returns to the client by adding a ResponseHeaderModifier filter. You can add, set (overwrite), and remove headers.

To modify response headers:

  1. Define an HTTPRoute for routing HTTP traffic to your service. Add a filter of type ResponseHeaderModifier. Then, in the responseHeaderModifier section, define add, set, and/or remove rules. In this example, we add an X-Frame-Options header, overwrite the value of the X-Powered-By header, and remove the Server header.

    response-headers-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: response-headers-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - example.com
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80
    filters:
    - type: ResponseHeaderModifier
    responseHeaderModifier:
    add:
    - name: X-Frame-Options
    value: DENY
    set:
    - name: X-Powered-By
    value: unicorns
    remove:
    - Server
    response-headers-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: response-headers-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - example.com
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80
    filters:
    - type: ResponseHeaderModifier
    responseHeaderModifier:
    add:
    - name: X-Frame-Options
    value: DENY
    set:
    - name: X-Powered-By
    value: unicorns
    remove:
    - Server
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f response-headers-route.yaml
    nix
    kubectl apply -f response-headers-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/response-headers-route created
    output
    text
    httproute.gateway.networking.k8s.io/response-headers-route created

Enable session persistence Jump to heading

When you enable session persistence, HAProxy Unified Gateway will place a cookie into the user’s browser that allows it to continue to route the user’s requests to the same backend pod that accepted the first request. This persistence will continue for the duration of the user’s session. This overrides the ordinary load balancing behavior so that the same pod can handle all of the user’s requests and maintain any in-memory state associated with that user. You won’t need this if your application is stateless.

To enable session persistence:

  1. Define an HTTPRoute for routing HTTP traffic to your service. In this example, we enable cookie-based session persistence for the web-svc backend service by including a sessionPersistence block. The session will persist for a maximum duration defined by absoluteTimeout. It will also end if the user is idle for the duration defined by idleTimeout.

    http-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: session-persistence
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80
    sessionPersistence:
    type: Cookie
    sessionName: "sticky-cookie"
    absoluteTimeout: 1h
    idleTimeout: 10m
    cookieConfig:
    lifetimeType: Session
    http-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: session-persistence
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: http-listener
    hostnames:
    - "example.com"
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80
    sessionPersistence:
    type: Cookie
    sessionName: "sticky-cookie"
    absoluteTimeout: 1h
    idleTimeout: 10m
    cookieConfig:
    lifetimeType: Session
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f http-route.yaml
    nix
    kubectl apply -f http-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/session-persistence created
    output
    text
    httproute.gateway.networking.k8s.io/session-persistence created

See also Jump to heading

Do you have any suggestions on how we can improve the content of this page?