How to Use Gateway API to Route Traffic in Kubernetes Clusters
Validated on 9 Feb 2026 • Last edited on 10 Feb 2026
DigitalOcean Kubernetes (DOKS) is a Kubernetes service with a fully managed control plane, high availability, and autoscaling. DOKS integrates with standard Kubernetes toolchains and DigitalOcean’s load balancers, volumes, CPU and GPU Droplets, API, and CLI.
Gateway API is a Kubernetes-native way to manage ingress traffic using standardized routing resources. It serves as an alternative to traditional ingress controllers like nginx and supports advanced routing features like header-based matching and traffic weighting.
DigitalOcean Kubernetes (DOKS) provides a managed Gateway API implementation using Cilium. The Gateway API is enabled by default on clusters with VPC-native networking running Kubernetes version 1.33 or later.
When you create a Gateway, DOKS automatically provisions a DigitalOcean Network Load Balancer to handle incoming traffic. Alternatively, you can provision an HTTP or internal load balancer.
Preserve Third-Party Gateway CRDs
DOKS installs and manages Gateway Custom Resource Definitions (CRDs) for Gateway, GatewayClass, HTTPRoute, TLSRoute, GRPCRoute, and ReferenceGrant by default. However, if you have Gateway CRDs from a third-party controller, then DOKS preserves those CRDs if one of the following conditions are met:
-
Manual opt-out: Gateway CRDs include the
doks.digitalocean.com/install-policy: "external"annotation. To add the annotation, run the following command for each CRD, replacing<your-crd-name>withgateways,gatewayclasses,httproutes,tlsroutes,grpcroutes, andreferencegrants:kubectl annotate crd <your-crd-name>.gateway.networking.k8s.io doks.digitalocean.com/install-policy="external" -
Automatic detection: Gateway CRDs include a
gateway.networking.k8s.io/bundle-versionannotation with a version newer than the version bundled with DOKS.
Prerequisites
To use Gateway API on DOKS, you need:
-
A DOKS cluster with VPC-native networking running Kubernetes 1.33 or later.
To confirm Gateway API is enabled on the cluster, run the following command:
kubectl get gatewayclass ciliumThe output looks similar to the following:
NAME CONTROLLER ACCEPTED AGE cilium io.cilium/gateway-controller True 7dIf the
ciliumGatewayClass exists and showsACCEPTED: True, Gateway API is enabled on your cluster. -
kubectlconnected to your cluster. See Connect to a DOKS Cluster. -
A backend service running in your cluster that you want to route traffic to.
Create a Gateway
A Gateway resource defines an entry point for traffic into your cluster. When you create a Gateway, DOKS automatically provisions a DigitalOcean Load Balancer.
The following example creates a Gateway that listens for HTTP traffic on port 80. The gatewayClassName field must be set to cilium, the DOKS-provided GatewayClass:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example-gateway
namespace: default
spec:
gatewayClassName: cilium
listeners:
- name: http
protocol: HTTP
port: 80For HTTPS traffic, see Configure TLS Termination. You can also customize the load balancer type and settings using annotations.
Apply the manifest:
kubectl apply -f gateway.yamlIt typically takes 1-2 minutes for DOKS to provision the load balancer and assign an external IP address. To check the Gateway status, run the following command:
kubectl get gateway example-gatewayThe output looks similar to the following:
NAME CLASS ADDRESS PROGRAMMED AGE
example-gateway cilium 203.0.113.10 True 2m
The ADDRESS column shows the external IP address of the provisioned load balancer. The PROGRAMMED: True status indicates that the Gateway is ready to accept traffic.
You can also verify that the load balancer is created by checking for the associated Kubernetes service:
kubectl get svc -l io.cilium.gateway/owning-gateway=example-gatewayNext, define the HTTP traffic routing rule as described in the following section.
Define HTTP Traffic Routing
An HTTPRoute resource defines how HTTP traffic reaching the Gateway routes to your backend services. HTTPRoutes reference a parent Gateway and specify rules for matching and routing requests, and advanced routing rules such as path-based or header-based routing.
The following example creates an HTTPRoute that routes all traffic from the Gateway to a backend service named my-service on port 80:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-route
namespace: default
spec:
parentRefs:
- name: example-gateway
rules:
- backendRefs:
- name: my-service
port: 80Apply the manifest:
kubectl apply -f httproute.yamlRoute Traffic Based on Path or Headers
You can configure more advanced routing rules to direct traffic based on request properties. The following examples show path-based and header-based routing:
The following example routes requests to /api to one service and requests to /web to another:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: path-based-route
namespace: default
spec:
parentRefs:
- name: example-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /web
backendRefs:
- name: web-service
port: 80The following example routes requests with a specific header to a different service:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-based-route
namespace: default
spec:
parentRefs:
- name: example-gateway
rules:
- matches:
- headers:
- type: Exact
name: X-Version
value: v2
backendRefs:
- name: api-v2-service
port: 8080For more advanced routing patterns like traffic splitting and request redirects, see the Gateway API HTTPRoute documentation.
Next, configure the TLS termination, as described in the following section.
Configure TLS Termination
You can terminate TLS at either the DigitalOcean Load Balancer or at the Gateway (Cilium) level. Choose the approach that best fits your needs:
- Load Balancer termination: Uses DigitalOcean-managed certificates and offloads TLS processing from your cluster.
- Gateway termination: Keeps TLS certificates within your cluster as Kubernetes Secrets.
If you need to terminate TLS at your backend pods, instead of the Gateway, you can use tls.mode: Passthrough in the Gateway manifest. See the Gateway API TLS documentation for details.
To terminate TLS at the load balancer, pass certificate annotations through the .spec.infrastructure.annotations field on the Gateway:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: https-gateway
namespace: default
spec:
gatewayClassName: cilium
infrastructure:
annotations:
service.beta.kubernetes.io/do-loadbalancer-certificate-id: "your-certificate-id"
service.beta.kubernetes.io/do-loadbalancer-protocol: "https"
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: example-certTo use a Let’s Encrypt certificate by name instead of ID, use the do-loadbalancer-certificate-name annotation:
infrastructure:
annotations:
service.beta.kubernetes.io/do-loadbalancer-certificate-name: "your-certificate-name"
service.beta.kubernetes.io/do-loadbalancer-protocol: "https"For more information about SSL certificates on load balancers, see SSL Certificates.
To terminate TLS at the Gateway, configure the load balancer for TLS passthrough and specify the certificate in the Gateway’s TLS configuration:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway-tls
namespace: default
spec:
gatewayClassName: cilium
infrastructure:
annotations:
service.beta.kubernetes.io/do-loadbalancer-tls-passthrough: "true"
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: my-tls-secret
kind: SecretThe TLS certificate must be stored in a Kubernetes Secret in the same namespace as the Gateway. To do this, add the following to your Secret config file:
apiVersion: v1
kind: Secret
metadata:
name: my-tls-secret
namespace: default
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-certificate>
tls.key: <base64-encoded-private-key>Configure Load Balancer Settings
You can configure additional load balancer settings by adding annotations to the Gateway’s .spec.infrastructure.annotations field. These annotations are the same as the ones you can configure for Load Balancer service for your cluster.
The following example configures a load balancer with a custom name and health check settings:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: custom-lb-gateway
namespace: default
spec:
gatewayClassName: cilium
infrastructure:
annotations:
service.beta.kubernetes.io/do-loadbalancer-name: "my-gateway-lb"
service.beta.kubernetes.io/do-loadbalancer-healthcheck-path: "/health"
service.beta.kubernetes.io/do-loadbalancer-healthcheck-protocol: "http"
listeners:
- name: http
protocol: HTTP
port: 80.spec.infrastructure.annotations field to 8 annotations. If you need more annotations, use a Load Balancer service directly with an ingress controller instead of the Gateway API to manage ingress traffic.
Use HTTP or Internal Load Balancers
By default, Gateway API provisions network load balancers, which route TCP and UDP traffic at the network layer. You can provision HTTP load balancers or internal load balancers instead by setting the appropriate annotations in the Gateway manifest.
HTTP load balancers operate at the application layer and can perform HTTP-specific functions. To use an HTTP load balancer:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http-lb-gateway
namespace: default
spec:
gatewayClassName: cilium
infrastructure:
annotations:
service.beta.kubernetes.io/do-loadbalancer-type: "REGIONAL"
listeners:
- name: http
protocol: HTTP
port: 80Internal load balancers are only accessible from within your VPC network. To use an internal load balancer:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: internal-gateway
namespace: default
spec:
gatewayClassName: cilium
infrastructure:
annotations:
service.beta.kubernetes.io/do-loadbalancer-network: "INTERNAL"
listeners:
- name: http
protocol: HTTP
port: 80For more information about load balancer types, see Load Balancer Type.
View Gateway Status
To view the status of your Gateways:
kubectl get gatewaysThe output looks similar to the following:
NAME CLASS ADDRESS PROGRAMMED AGE
example-gateway cilium 203.0.113.10 True 5m
The True status of the PROGRAMMED: column indicates the Gateway is ready to route traffic. The ADDRESS column shows the load balancer’s external IP address. You can also use kubectl describe gateway <name> to view detailed information, or kubectl get httproutes to list routes.
Additional Resources
For more information about Gateway API, see:
Official Kubernetes Gateway API specification and guides.
Cilium’s implementation of the Gateway API.
Tutorial on setting up HTTPS routing with Gateway API.
Tutorial on replacing Ingress with Cilium Gateway for HTTP traffic.