HTTP/2
You might have services in your Kubernetes cluster that use HTTP/2 for communication. Typically these are gRPC services, but it could apply to any service that uses HTTP/2 in its transport layer. To enable HTTP/2 communication, you simply set the app protocol on the service to HTTP/2. This setting instructs kgateway to use HTTP/2 for communication with the destination.
Before you begin
-
Follow the Get started guide to install kgateway.
-
Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.
-
Get the external address of the gateway and save it in an environment variable.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESS
kubectl port-forward deployment/http -n kgateway-system 8080:8080
Enable access logging
Enable access logging on the Gateway. You can use the access logs later to verify that the request used the HTTP/2 protocol.
kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: HTTPListenerPolicy
metadata:
name: access-logs
namespace: kgateway-system
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: http
accessLog:
- fileSink:
path: /dev/stdout
jsonFormat:
start_time: "%START_TIME%"
method: "%REQ(X-ENVOY-ORIGINAL-METHOD?:METHOD)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
protocol: "%PROTOCOL%"
response_code: "%RESPONSE_CODE%"
response_flags: "%RESPONSE_FLAGS%"
bytes_received: "%BYTES_RECEIVED%"
bytes_sent: "%BYTES_SENT%"
total_duration: "%DURATION%"
resp_backend_service_time: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
req_x_forwarded_for: "%REQ(X-FORWARDED-FOR)%"
user_agent: "%REQ(USER-AGENT)%"
request_id: "%REQ(X-REQUEST-ID)%"
authority: "%REQ(:AUTHORITY)%"
backendHost: "%UPSTREAM_HOST%"
backendCluster: "%UPSTREAM_CLUSTER%"
EOF
HTTP/2 for in-cluster services
To demonstrate the HTTP/2 routing capabilities, deploy a sample nginx server and configure it to only accept HTTP/2 connections.
-
Deploy a simple nginx server that is configured to use the HTTP/2 protocol. Note that in this example, the
appProtocol
on the nginx service is set tohttp2
. Other supported values to configure the HTTP/2 protocol includegrpc
,grpc-web
, orkubernetes.io/h2c
.kubectl apply -f- <<EOF apiVersion: v1 kind: ConfigMap metadata: name: nginx-conf data: nginx.conf: | user nginx; worker_processes 1; events { worker_connections 10240; } http { server { listen 80 http2; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } } } --- apiVersion: v1 kind: Service metadata: name: nginx spec: selector: app.kubernetes.io/name: nginx ports: - protocol: TCP port: 8080 targetPort: http-web-svc appProtocol: http2 --- apiVersion: v1 kind: Pod metadata: name: nginx labels: app.kubernetes.io/name: nginx spec: containers: - name: nginx image: nginx:stable ports: - containerPort: 80 name: http-web-svc volumeMounts: - name: nginx-conf mountPath: /etc/nginx/nginx.conf subPath: nginx.conf readOnly: true volumes: - name: nginx-conf configMap: name: nginx-conf items: - key: nginx.conf path: nginx.conf EOF
-
Verify that the nginx server is up and running.
kubectl get pods | grep nginx
Example output:
nginx 1/1 Running 0 15s
-
Create an HTTPRoute to expose the nginx server on the Gateway.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: nginx namespace: default spec: parentRefs: - name: http namespace: kgateway-system hostnames: - http2.example.com rules: - backendRefs: - name: nginx port: 8080 EOF
-
Send a request to the nginx server and include the
--http2-prior-knowledge
option to send an HTTP/2 request to the Gateway. Verify that the request succeeds and that you get back a 200 HTTP response code.curl -vik http://$INGRESS_GW_ADDRESS:8080/ -H "host: http2.example.com:8080" --http2-prior-knowledge
curl -i localhost:8080/ -H "host: http2.example.com" --http2-prior-knowledge
Example output:
... > GET / HTTP/2 > Host: http2.example.com:8080 > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/2 200 HTTP/2 200 ... <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
-
Get the access logs of your gateway proxy.
kubectl -n kgateway-system logs deployments/http | tail -1 | jq --sort-keys
Example output:
{ "authority": "http2.example.com:8080", "backendCluster": "kube_default_nginx_8080", "backendHost": "10.0.2.26:80", "bytes_received": 0, "bytes_sent": 615, "method": "GET", "path": "/", "protocol": "HTTP/2", "req_x_forwarded_for": "10.0.15.215", "request_id": "c996b154-9299-4f00-b356-8cc66472e613", "resp_backend_service_time": "0", "response_code": 200, "response_flags": "-", "start_time": "2025-06-23T16:23:09.615Z", "total_duration": 0, "user_agent": "curl/8.7.1" }
HTTP/2 for external services
-
Create a Backend resource that represents your external service. In this example, you configure a Backend for the
https://nghttp2.org/httpbin/
domain. This domain requires requests to be sent with the HTTP/2 protocol.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: Backend metadata: name: http2 spec: type: Static static: hosts: - host: nghttp2.org port: 80 appProtocol: http2 EOF
-
Create an HTTPRoute that routes requests to your Backend.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: http2 namespace: default spec: parentRefs: - name: http namespace: kgateway-system hostnames: - static.example rules: - backendRefs: - name: http2 kind: Backend group: gateway.kgateway.dev filters: - type: URLRewrite urlRewrite: hostname: nghttp2.org path: type: ReplacePrefixMatch replacePrefixMatch: /httpbin/ EOF
-
Send a request to the
static.example
domain. The request is forwarded to thenghttp2.org/httpbin/
path, which only accepts HTTP/2 requests. Verify that the request succeeds and that you get back a 200 HTTP response code.curl -vik http://$INGRESS_GW_ADDRESS:8080/ -H "host: static.example:8080" --http2-prior-knowledge
curl -i localhost:8080/ -H "host: static.example" --http2-prior-knowledge
Example output:
... > GET / HTTP/2 > Host: static.example:8080 > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/2 200 HTTP/2 200 < content-type: text/html; charset=utf-8 content-type: text/html; charset=utf-8 < content-length: 9649 content-length: 9649 < access-control-allow-origin: * access-control-allow-origin: * < access-control-allow-credentials: true access-control-allow-credentials: true < x-backend-header-rtt: 6.191667 x-backend-header-rtt: 6.191667 < alt-svc: h3=":443"; ma=3600 alt-svc: h3=":443"; ma=3600 < server: envoy server: envoy < via: 1.1 nghttpx via: 1.1 nghttpx < x-frame-options: SAMEORIGIN x-frame-options: SAMEORIGIN < x-xss-protection: 1; mode=block x-xss-protection: 1; mode=block < x-content-type-options: nosniff x-content-type-options: nosniff < x-envoy-upstream-service-time: 6504 x-envoy-upstream-service-time: 6504 < ...
-
Get the access logs of your gateway proxy.
kubectl -n kgateway-system logs deployments/http | tail -1 | jq --sort-keys
Example output:
{ "authority": "nghttp2.org", "backendCluster": "backend_default_http2_0", "backendHost": "139.162.123.134:80", "bytes_received": 0, "bytes_sent": 9649, "method": "GET", "path": "/", "protocol": "HTTP/2", "req_x_forwarded_for": "10.0.9.76", "request_id": "6e8baf82-2c2b-40cc-b5c0-d2d2295d3abf", "resp_backend_service_time": "313", "response_code": 200, "response_flags": "-", "start_time": "2025-06-23T16:25:22.639Z", "total_duration": 314, "user_agent": "curl/8.7.1" }
Cleanup
You can remove the resources that you created in this guide.kubectl delete httproute nginx
kubectl delete pod nginx
kubectl delete service nginx
kubectl delete configmap nginx-conf
kubectl delete backend http2
kubectl delete httproute http2