Cart

    Sorry, we could not find any results for your search querry.

    Configuring a Kubernetes Gateway

    In a Kubernetes cluster, you can route HTTP and HTTPS traffic using the Kubernetes Gateway API. A Gateway replaces the traditional Ingress Controller and gives you a central place for SSL (TLS) termination, routing rules and security.

    In this guide, you’ll configure a Kubernetes Gateway step by step for a simple demo application. First you deploy an app and Service, then you configure a Gateway and HTTPRoute and add SSL security with a TLS certificate (for example via Cert-manager and Let’s Encrypt). At the end, you’ll test whether HTTPS works correctly.

    For this guide you’ll need:

    • A Kubernetes cluster.
    • A Gateway controller such as Traefik or Cilium. For example, follow our Traefik guide first.
    • Cert-manager: the Gateway API’s HTTPS listeners only support Kubernetes Secrets (not .json); Cert-manager uses Secrets, Traefik uses .json. For this reason, you’ll need Cert-manager in this setup to generate SSL certificates.
    • Kubectl
    • A domain name whose DNS points to the gateway (Traefik or Cilium).
     

     

    What is a Kubernetes Gateway?

     

    The Kubernetes Gateway API introduces new resource types, such as GatewayClass, Gateway and HTTPRoute. These resources describe how traffic flows from outside into your cluster and which Services are allowed to receive that traffic. Unlike a classic Ingress, the Gateway API clearly separates the role of infrastructure management (GatewayClass/Gateway) and application routing (HTTPRoute).

    Broadly speaking, a Gateway setup looks like this:

    • A GatewayClass describes which type of gateway controller you use (for example Traefik, NGINX or Cilium).
    • A Gateway defines one or more listeners (for example HTTP on port 8000 and HTTPS on port 8443) with (sub)domains (hostnames) and TLS settings.
    • An HTTPRoute maps (sub)domains and paths to Services in a namespace.

    In this tutorial, you’ll create your own Gateway in a separate namespace, configure an HTTPRoute and add SSL termination to the Gateway. This means you don’t have to manage TLS certificates per app, but centrally on the Gateway.


     

    Deploying a demo application behind the Gateway

     

    TL;DR: the quickest copy-and-paste

    Create a file, for example gateway-demo.yaml, with the contents below. 

    • At the very least, replace demo.voorbeeld.nl with your own domain and, if you wish, the namespace name as well:
    apiVersion: v1
    kind: Namespace
    metadata:
      name: demo-gateway
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: demo-app
      namespace: demo-gateway
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: demo-app
      template:
        metadata:
          labels:
            app: demo-app
        spec:
          containers:
          - name: demo-app
            image: traefik/whoami
            ports:
            - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-app
      namespace: demo-gateway
    spec:
      selector:
        app: demo-app
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: demo-gateway
      namespace: demo-gateway
    spec:
      gatewayClassName: traefik
      listeners:
      - name: web
        protocol: HTTP
        port: 8000
        hostname: demo.voorbeeld.nl
        allowedRoutes:
          namespaces:
            from: Same
      - name: websecure
        protocol: HTTPS
        port: 8443
        hostname: demo.voorbeeld.nl
        tls:
          mode: Terminate
          certificateRefs:
          - kind: Secret
            name: demo-gateway-tls
        allowedRoutes:
          namespaces:
            from: Same
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: demo-route-redirect
      namespace: demo-gateway
    spec:
      parentRefs:
      - name: demo-gateway
        sectionName: web
      hostnames:
      - demo.voorbeeld.nl
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /
        filters:
        - type: RequestRedirect
          requestRedirect:
            scheme: https
            statusCode: 301
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: demo-route
      namespace: demo-gateway
    spec:
      parentRefs:
      - name: demo-gateway
        sectionName: websecure
      hostnames:
      - demo.voorbeeld.nl
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /
        backendRefs:
        - name: demo-app
          port: 80
    

    Next, create a namespace for your gateway and apply the .yaml file:

    kubectl create namespace demo-gateway
    kubectl apply -f gateway-demo.yaml
     
     

    You’ll need an application behind the Gateway to test your configuration. In this example, you’ll use a simple HTTP ‘whoami’ service on port 80 with a Deployment and Service. The app runs as a container in the cluster; for more background, read our explanation of what a container image is.


     

    Step 1

    Create a separate namespace for the demo app and the Gateway resources:

    kubectl create namespace demo-gateway

    The demo-gateway namespace helps to logically separate the demo resources from the rest of your cluster.


     

    Step 2

    Create the file demo-app.yaml on your computer/laptop with the following contents:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: demo-gateway
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: demo-app
      namespace: demo-gateway
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: demo-app
      template:
        metadata:
          labels:
            app: demo-app
        spec:
          containers:
          - name: demo-app
            image: traefik/whoami
            ports:
            - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-app
      namespace: demo-gateway
    spec:
      selector:
        app: demo-app
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP

    The Deployment starts two replicas of the traefik/whoami container (a small HTTP service that returns request information) and the Service makes these pods reachable on port 80 within the namespace.


     

    Step 3

    Deploy the demo application:

    kubectl apply -f demo-app.yaml

    Then check that the pods are running:

    kubectl get pods -n demo-gateway

    Once the pods are in the Running state, your backend is ready to be exposed via the Gateway.


     

    Step 4

    Now that the backend is running, first configure a GatewayClass (often already present). In this example, we’ll assume a Gateway controller such as Traefik that supports the Gateway API.

    Check whether (and which) GatewayClasses are already present in your cluster:

    kubectl get gatewayclass

    If your provider or gateway controller has already created a GatewayClass (for example traefik), use that name in your Gateway and continue to step 5. 

    Don’t see a GatewayClass yet? Then add one yourself. For example, if you want to define a GatewayClass for Traefik, create a file gatewayclass.yaml with the following contents:

    apiVersion: gateway.networking.k8s.io/v1
    kind: GatewayClass
    metadata:
      name: traefik
    spec:
      controllerName: traefik.io/gateway-controller

    Adjust the name if your controller expects a different GatewayClass (you can find this in the documentation for the GatewayClass you’re using). The controllerName value identifies which controller manages Gateways of this type; in this example, that’s the Traefik Gateway controller.

    kubectl apply -f gatewayclass.yaml

    With this step, you link the Gateway API to your chosen gateway controller.


     

    Step 5

    Create a .yaml file with the definition of the actual Gateway for HTTP and HTTPS traffic, for example demo-gateway-listener.yaml, with the contents below.

    Use your own domain instead of demo.voorbeeld.nl, the correct namespace (here demo-gateway) and the GatewayClass name (traefik in the example):

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: demo-gateway
      namespace: demo-gateway
    spec:
      gatewayClassName: traefik
      listeners:
      - name: web
        protocol: HTTP
        port: 8000
        hostname: demo.voorbeeld.nl
        allowedRoutes:
          namespaces:
            from: Same
      - name: websecure
        protocol: HTTPS
        port: 8443
        hostname: demo.voorbeeld.nl
        tls:
          mode: Terminate
          certificateRefs:
          - kind: Secret
            name: demo-gateway-tls
        allowedRoutes:
          namespaces:
            from: Same

     

    Step 6

    Deploy the Gateway:

    kubectl apply -f demo-gateway-listener.yaml

    This Gateway listens on port 8000 for HTTP traffic to demo.voorbeeld.nl and on port 8443 for HTTPS traffic. The allowedRoutes.namespaces.from: Same setting restricts routes to the same namespace as the Gateway (demo-gateway), which is safer in multi-tenant environments.


     

    Step 7

    Create an HTTPRoute that maps the (sub)domain/hostname and the path to the demo Service. For example, create the file httproute.yaml with the following contents:

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: demo-route
      namespace: demo-gateway
    spec:
      parentRefs:
      - name: demo-gateway
        sectionName: websecure
      hostnames:
      - demo.voorbeeld.nl
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /
        backendRefs:
        - name: demo-app
          port: 80

    The parentRefs link the route to the demo-gateway Gateway. All paths under / are sent to the demo-app Service on port 80.


     

    Step 8

    Apply the HTTPRoute to your Kubernetes cluster:

    kubectl apply -f httproute.yaml

    Then check whether the Gateway and HTTPRoute are ‘Ready’:

    kubectl get gateway -n demo-gateway
    kubectl get httproute -n demo-gateway

    Use kubectl describe for more details if the status is not ‘Programmed’ or ‘Accepted’. Any messages in the conditions provide a clue as to what’s wrong (for example, an unknown GatewayClass or (sub)domain/hostname).


     

    Step 9

    Now that HTTP works, add SSL security. In Kubernetes, that usually means TLS termination on the Gateway (via the ClusterIssuer created with Cert-manager): the Gateway presents the certificate to the client and forwards the traffic as unencrypted HTTP to the backend. The certificate is stored in a Secret in the same namespace as the Gateway.

    Create a Certificate resource so that Cert-manager automatically requests a certificate for your domain. Use the name of your (Cluster)Issuer, for example letsencrypt-issuer. Create the file certificate.yaml with the following contents:

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: demo-cert
      namespace: demo-gateway
    spec:
      secretName: demo-gateway-tls
      issuerRef:
        name: letsencrypt-issuer
        kind: ClusterIssuer
      dnsNames:
      - demo.voorbeeld.nl

    The dnsNames and secretName fields must match your (sub)domain/hostname and the name you’ll use in the Gateway in a moment. Cert-manager stores the issued certificate and the private key in the demo-gateway-tls Secret.


     

    Step 10

    Apply the certificate.yaml you just created to your Kubernetes cluster:

    kubectl apply -f certificate.yaml

    To be safe, check that the certificate has been created successfully:

    kubectl describe certificate demo-cert -n demo-gateway

    Pay attention to the conditions; if the status is Ready and there are no DNS or HTTP challenge errors, the Secret containing the certificate is available. With -n demo-gateway you specify which namespace the Certificate is in.


     

    Step 11

    Finally, test whether HTTPS works using, for example, a curl command, or navigate to the (sub)domain in your browser:

    curl -v https://demo.voorbeeld.nl

    You should see a TLS handshake followed by the output from the whoami service. If your browser no longer shows warnings about an unsafe certificate, your SSL security is configured correctly.


     

    Forwarding the original visitor IP address with Traefik

     

    With PROXY protocol, the TransIP load balancer forwards a visitor’s original IP address to Traefik. Traefik processes this information and forwards the visitor address to your application through HTTP headers, such as X-Forwarded-For. This setting applies to the Traefik entryPoints used by your Gateway; it does not require additional fields in the Gateway or HTTPRoute.

    These instructions apply to Traefik behind a TransIP LoadBalancer Service. Other Gateway controllers have their own settings. Configure Traefik first, then enable PROXY protocol on the load balancer. The change applies to all Gateways and Ingress routes on the affected entryPoints. 

     

    Step 1

    Open a terminal on Linux or macOS, or PowerShell on Windows, on the computer you use to manage the cluster. Check the active cluster, the installed Traefik release and its Service:

    kubectl config current-context
    helm list --namespace traefik
    kubectl get service --namespace traefik

    The --namespace option selects the namespace where Traefik is installed. Using a different namespace? Replace traefik with that name. Note the release name and chart version from the CHART column. For traefik-39.0.0, the chart version is 39.0.0, for example. In the following steps, use the LoadBalancer Service that forwards traffic to Traefik, rather than the demo-app Service.


     

    Step 2

    Create the file traefik-proxy.yaml. On Linux or macOS, open it with:

    nano traefik-proxy.yaml

    On Windows with Powershell, open it with:

    notepad.exe traefik-proxy.yaml

    Add the following content:

    ports:
      web:
        proxyProtocol:
          trustedIPs:
            - "89.41.168.0/26"
      websecure:
        proxyProtocol:
          trustedIPs:
            - "89.41.168.0/26"

    The trustedIPs list determines which senders Traefik accepts PROXY information from. The range 89.41.168.0/26 is our load balancer range.  Add only trusted load balancer addresses or networks. Do not use 0.0.0.0/0 or proxyProtocol.insecure: true; these also trust information supplied by a visitor.

    Save the file. Close nano with ctrl + x > y > enter. In Notepad, select ‘File’ > ‘Save’ and check that the filename ends in .yaml rather than .yaml.txt.


     

    Step 3

    Apply the settings using the same chart version as your existing installation. Replace <chartversion> with the version from step one and adjust the release name traefik if yours differs:

    helm upgrade traefik traefik/traefik --namespace traefik --version <chartversion> --reuse-values -f traefik-proxy.yaml
    kubectl rollout status deployment/traefik --namespace traefik --timeout=180s
    • The --version option retains the existing chart version. 
    • The --reuse-values option retains the existing Helm settings
    • -f adds the settings from the file
    • With --timeout=180s, kubectl waits up to three minutes for the rollout. 

    Use your Deployment name if it differs. Managing Traefik with GitOps? Add the same settings to the configuration managed by your GitOps controller.


     

    Step 4

    Enable PROXY protocol on the Traefik LoadBalancer Service. Open the Service in your default editor:

    kubectl edit service traefik --namespace traefik

    Replace the Service name traefik with the name from step one if it differs. Under metadata.annotations, add the following annotation or change its existing value:

    service.beta.kubernetes.io/transip-loadbalancer-protocol: "proxy"

    Under spec, also set the following value:

    externalTrafficPolicy: Local

    Save the change and close the editor. Local prevents Kubernetes from replacing the sender address when routing to another node. Only nodes with a local, available Traefik Pod receive traffic. Check that enough Traefik replicas are available. Also record the annotation and externalTrafficPolicy in your existing Helm values or GitOps configuration so that subsequent deployments retain them.


     

    Step 5

    Send a request from your own computer to the domain used in this tutorial:

    curl https://demo.voorbeeld.nl

    In Windows PowerShell, use curl.exe if curl is an installed alias for Invoke-WebRequest. Check the X-Forwarded-For header in the whoami application’s output. It should contain your internet connection’s public address. Using a VPN or an additional proxy in front of the load balancer? You may see that intermediary connection’s address. RemoteAddr usually shows Traefik’s internal address because Traefik opens a new connection to the backend.

    Configure your own application or web server to process forwarded headers only from the trusted Traefik proxy. The backend does not need to process PROXY protocol for this HTTPRoute: Traefik receives PROXY protocol and forwards the visitor information as HTTP headers. Never blindly trust the first address in an X-Forwarded-For header supplied by a client.

    If the visitor address is missing, check that both entryPoints use the correct trustedIPs, the Service annotation is set to proxy and the request goes through the public load balancer. For background information, see the Traefik documentation on PROXY protocol and entryPoints.


     

    Troubleshooting: common mistakes

     

    Still not able to reach your application via HTTPS? The checks below will help you resolve the most common issues.


     

    Step 1

    Verify that the backend Service and pods are working:

    kubectl get svc -n demo-gateway
    kubectl get pods -n demo-gateway
    kubectl logs -l app=demo-app -n demo-gateway

    If the pods are crashing or not receiving traffic, fix that first before looking further at the Gateway configuration.


     

    Step 2

    Check DNS and reachability:

    nslookup demo.voorbeeld.nl
    ping demo.voorbeeld.nl

    If the (sub)domain/hostname does not point to the correct IP address or returns an error, check your domain’s DNS settings and your nameservers.


     

    Step 3

    Check the status of the Gateway and HTTPRoute:

    kubectl describe gateway demo-gateway -n demo-gateway
    kubectl describe httproute demo-route -n demo-gateway

    Look for conditions such as Programmed and Accepted and any error messages (for example, an unknown GatewayClass, an incorrect (sub)domain/hostname or a missing listener). These fields usually indicate straight away where the configuration is conflicting.


     

    Step 4

    Check that the TLS certificate and the Secret exist and are ‘Ready’:

    kubectl get certificate -n demo-gateway
    kubectl get secret demo-gateway-tls -n demo-gateway

    If the Secret is missing or the certificate is not Ready, view Cert-manager’s events with kubectl describe certificate and resolve any HTTP or DNS challenge issues (for example, incorrect DNS records or firewall rules).


     

    In this guide, you set up a Kubernetes Gateway for a demo application, configured HTTP and HTTPS listeners, linked a TLS certificate via Cert-manager and added an HTTP->HTTPS redirect. With this approach, you centralise your SSL security, make routing rules easier to manage, and you’re ready to use more advanced Kubernetes Gateway API features, such as multiple hostnames, per-environment paths and additional security filters.

    Need help?

    Receive personal support from our supporters

    Contact us