Set the Host header sent to a Service

Deployment Platform
Related Documentation
Related Resources
Minimum Version
Kong Operator - 2.2
TL;DR

Annotate the Kubernetes Service with konghq.com/host-header: "your-hostname". Kong Gateway will use this value as the Host header when forwarding requests upstream instead of the Pod IP address.

Prerequisites

If you don’t have a Konnect account, you can get started quickly with our onboarding wizard.

  1. The following Konnect items are required to complete this tutorial:
    • Personal access token (PAT): Create a new personal access token by opening the Konnect PAT page and selecting Generate Token.
  2. Set the personal access token as an environment variable:

    export KONNECT_TOKEN='YOUR KONNECT TOKEN'

If you want cert-manager to issue and rotate the admission and conversion webhook certificates, install cert-manager to your cluster and enable cert-manager integration by passing the following argument while installing, in the next step:

   --set global.webhooks.options.certManager.enabled=true

If you do not enable this, the chart will generate and inject self-signed certificates automatically. We recommend enabling cert-manager to manage the lifecycle of these certificates. Kong Operator needs a certificate authority to sign the certificate for mTLS communication between the control plane and the data plane. This is handled automatically by the Helm chart. If you need to provide a custom CA certificate, refer to the certificateAuthority section in the values.yaml of the Helm chart to learn how to create and reference your own CA certificate.

Apply a KongLicense. This assumes that your license is available in ./license.json

echo "
apiVersion: configuration.konghq.com/v1alpha1
kind: KongLicense
metadata:
 name: kong-license
rawLicenseString: '$(cat ./license.json)'
" | kubectl apply -f -
kubectl create namespace kong --dry-run=client -o yaml | kubectl apply -f -
echo '
kind: KonnectAPIAuthConfiguration
apiVersion: konnect.konghq.com/v1alpha1
metadata:
  name: konnect-api-auth
  namespace: kong
spec:
  type: token
  token: "'$KONNECT_TOKEN'"
  serverURL: us.api.konghq.com
' | kubectl apply -f -

Create the kong namespace:

kubectl create namespace kong

Create the kong namespace:

kubectl create namespace kong --dry-run=client -o yaml | kubectl apply -f -

Create the GatewayConfiguration, GatewayClass, and Gateway resources with basic configuration:

Setting spec.konnect.authRef attaches the data plane to Konnect, which manages its configuration:

echo '
apiVersion: gateway-operator.konghq.com/v2beta1
kind: GatewayConfiguration
metadata:
  name: gateway-configuration
  namespace: kong
spec:
  konnect:
    authRef:
      name: konnect-api-auth
      namespace: kong
  dataPlaneOptions:
    deployment:
      podTemplateSpec:
        spec:
          containers:
            - image: kong/kong-gateway:3.16
              name: proxy
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: gateway-class
spec:
  controllerName: konghq.com/gateway-operator
  parametersRef:
    group: gateway-operator.konghq.com
    kind: GatewayConfiguration
    name: gateway-configuration
    namespace: kong
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong
  namespace: kong
  annotations:
    gateway-operator.konghq.com/static-naming: "true"
spec:
  gatewayClassName: gateway-class
  listeners:
    - name: http
      port: 80
      protocol: HTTP' | kubectl apply -f -

The gateway-operator.konghq.com/static-naming: "true" annotation gives the resources Kong Operator generates for the Gateway static, predictable names: the KonnectGatewayControlPlane it creates for the Gateway is named after the Gateway, in this case kong. You can reference that control plane from other resources before it exists, and its name in Konnect is derived from the Gateway name.

echo '
apiVersion: gateway-operator.konghq.com/v2beta1
kind: GatewayConfiguration
metadata:
  name: gateway-configuration
  namespace: kong
spec:
  dataPlaneOptions:
    deployment:
      podTemplateSpec:
        spec:
          containers:
            - image: kong/kong-gateway:3.16
              name: proxy
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: gateway-class
spec:
  controllerName: konghq.com/gateway-operator
  parametersRef:
    group: gateway-operator.konghq.com
    kind: GatewayConfiguration
    name: gateway-configuration
    namespace: kong
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong
  namespace: kong
spec:
  gatewayClassName: gateway-class
  listeners:
    - name: http
      port: 80
      protocol: HTTP' | kubectl apply -f -
  1. Run the following command to create a sample httpbin Service:

    kubectl apply -f https://developer.konghq.com/manifests/kic/httpbin-service.yaml -n kong
  2. Create an HTTPRoute resource:

    echo '
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin-route
      namespace: kong
      annotations:
        konghq.com/strip-path: "true"
        konghq.com/preserve-host: "false"
    spec:
      parentRefs:
        - name: kong
      rules:
        - matches:
            - path:
                type: PathPrefix
                value: /httpbin
          backendRefs:
            - name: httpbin
              kind: Service
              port: 80' | kubectl apply -f -

By default, Kong Gateway sets the Host header to the IP address of the individual Pod it forwards the request to. Some upstream services perform host-based virtual hosting or access control and require a specific Host header value. You can override this behavior using the konghq.com/host-header annotation.

Check the default behavior

  1. Wait for the Gateway to be programmed:

    kubectl wait --for=condition=Programmed gateway/kong -n kong --timeout=5m
  2. Get the Gateway’s external IP address:

    export PROXY_IP=$(kubectl get gateway kong -n kong -o jsonpath='{.status.addresses[0].value}')
  3. Send a request to the /headers endpoint, which returns all request headers received by the upstream service:

    curl "http://$PROXY_IP/httpbin/headers" \
         --no-progress-meter --fail-with-body 
    curl "http://$PROXY_IP/httpbin/headers" \
         --no-progress-meter --fail-with-body 

    The response shows the headers the upstream received. The Host header will contain the Pod IP address assigned by Kong Gateway:

    {
      "headers": {
        "Host": "10.0.0.5",
        ...
      }
    }

Annotate the Service

Annotate the httpbin Service to set a custom Host header:

kubectl annotate service httpbin -n kong \
  konghq.com/host-header="internal.example.com"

Validate

Send the same request again:

curl -s $PROXY_IP/httpbin/headers

The Host header in the upstream request now reflects the configured value:

{
  "headers": {
    "Host": "internal.example.com",
    ...
  }
}

Note: If the client-side Host header must be preserved instead, use the konghq.com/preserve-host: "true" annotation on the HTTPRoute or Ingress resource. When preserve-host is set to true, it takes precedence over konghq.com/host-header.

Cleanup

Deleting the Gateway also deletes the control plane and data plane resources Kong Operator created for it. Deleting the kong-system namespace removes the operator:

kubectl delete -n kong --ignore-not-found \
  httproute/httpbin-route \
  service/httpbin \
  gateway/kong \
  gatewayconfiguration/gateway-configuration
kubectl delete --ignore-not-found gatewayclass/gateway-class
kubectl delete --ignore-not-found namespace kong
helm uninstall kong-operator -n kong-system
kubectl delete --ignore-not-found namespace kong-system

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!