TCPRoute

Learn how to configure a TCPRoute to establish a TCP connection between NGINX Gateway Fabric and the backend applications.

Overview

TCPRoute is a Gateway API resource that is used to configure routing for TCP connections. When attached to a Gateway listener, it forwards connections arriving on the listener’s port to one or more backend Services. In this guide, you will configure two TCPRoutes for coffee and tea applications, and see how listeners are attached to backends to route TCP traffic.

Note on Gateway API Experimental Features

Important
TCPRoute is a Gateway API resource from the experimental release channel.

To use Gateway API experimental resources, the Gateway API resources from the experimental channel must be installed before deploying NGINX Gateway Fabric. Additionally, NGINX Gateway Fabric must have experimental features enabled.

Caution
As noted in the Gateway API documentation, future releases of the Gateway API can include breaking changes to experimental resources and fields.

To install the Gateway API resources from the experimental channel, run the following:

kubectl kustomize "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/experimental?ref=v2.2.1" | kubectl apply -f -
If you plan to use the edge version of NGINX Gateway Fabric, you can replace the version in ref with main, for example ref=main.

To enable experimental features on NGINX Gateway Fabric:

Using Helm: Set nginxGateway.gwAPIExperimentalFeatures.enable to true. An example can be found in the Installation with Helm guide.

Using Kubernetes manifests: Add the --gateway-api-experimental-features command-line flag to the deployment manifest args. An example can be found in the Installation with Kubernetes manifests guide.

Before you begin

  • Install NGINX Gateway Fabric with experimental features enabled.

Setup

Create two simple applications coffee and tea by copying and pasting the following block into your terminal:

yaml
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee
spec:
  replicas: 1
  selector:
    matchLabels:
      app: coffee
  template:
    metadata:
      labels:
        app: coffee
    spec:
      containers:
      - name: coffee
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: coffee
spec:
  ports:
  - port: 8081
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tea
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tea
  template:
    metadata:
      labels:
        app: tea
    spec:
      containers:
      - name: tea
        image: nginxdemos/nginx-hello:plain-text
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: tea
spec:
  ports:
  - port: 8082
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: tea
EOF

This creates two Services and Deployments for coffee and tea applications. Run the following command to verify the resources were created:

kubectl get pods,svc
text
NAME                                 READY   STATUS    RESTARTS   AGE
pod/coffee-64f4877d66-22hhn          1/1     Running   0          3m1s
pod/tea-8cf894c7c-d2sfm              1/1     Running   0          3m1s

NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
service/coffee          ClusterIP   10.96.168.222   <none>        81/TCP          3m1s
service/tea             ClusterIP   10.96.16.136    <none>        82/TCP          3m1s

Create a Gateway with two TCP listeners:

yaml
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
spec:
  gatewayClassName: nginx
  listeners:
  - name: coffee
    protocol: TCP
    port: 81
    allowedRoutes:
      kinds:
      - kind: TCPRoute
  - name: tea
    protocol: TCP
    port: 82
    allowedRoutes:
      kinds:
      - kind: TCPRoute
EOF

This Gateway defines two TCP listeners on ports 81 (coffee) and 82 (tea), and allows only TCPRoute resources to attach to them. After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. Verify the gateway is created:

kubectl describe gateways.gateway.networking.k8s.io gateway

Verify the status is Accepted:

text
Status:
  Addresses:
    Type:   IPAddress
    Value:  10.96.36.219
  Conditions:
    Last Transition Time:  2026-01-09T05:40:37Z
    Message:               The Gateway is accepted
    Observed Generation:   1
    Reason:                Accepted
    Status:                True
    Type:                  Accepted
    Last Transition Time:  2026-01-09T05:40:37Z
    Message:               The Gateway is programmed
    Observed Generation:   1
    Reason:                Programmed
    Status:                True
    Type:                  Programmed

Save the public IP address and port(s) of the Gateway into shell variables:

text
GW_IP=XXX.YYY.ZZZ.III
GW_PORT_1=<Listener-1 Port number>
GW_PORT_2=<Listener-2 Port number>
In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.

Create TCPRoutes for routing to coffee and tea applications:

yaml
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: tcp-coffee
spec:
  parentRefs:
  - name: gateway
    sectionName: coffee
  rules:
  - backendRefs:
    - name: coffee
      port: 8081
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: tcp-tea
spec:
  parentRefs:
  - name: gateway
    sectionName: tea
  rules:
  - backendRefs:
    - name: tea
      port: 8082
EOF

This configuration creates two TCPRoutes:

  • tcp-coffee attaches to the Gateway listener named coffee on port 81 and forwards TCP connections to the coffee application.
  • tcp-tea attaches to the Gateway listener named tea on port 82 and forwards TCP connections to the tea application.

Verify the status of the TCPRoutes and they have the Accepted condition:

kubectl describe tcproutes.gateway.networking.k8s.io

You should see a similar status for both TCPRoutes tcp-coffee and tcp-tea:

text
Status:
  Parents:
    Conditions:
      Last Transition Time:  2026-01-09T05:04:15Z
      Message:               The Route is accepted
      Observed Generation:   1
      Reason:                Accepted
      Status:                True
      Type:                  Accepted
      Last Transition Time:  2026-01-09T05:04:15Z
      Message:               All references are resolved
      Observed Generation:   1
      Reason:                ResolvedRefs
      Status:                True
      Type:                  ResolvedRefs
    Controller Name:         gateway.nginx.org/nginx-gateway-controller
    Parent Ref:
      Group:         gateway.networking.k8s.io
      Kind:          Gateway
      Name:          gateway
      Namespace:     default

Next, verify that the TCPRoutes are configured by inspecting the NGINX configuration:

kubectl exec -it deployments/gateway-nginx -- nginx -T

The NGINX configuration should look something like:

text
server {
    listen 81;
    listen [::]:81;
    proxy_pass default_coffee_8081;
}
server {
    listen 82;
    listen [::]:82;
    proxy_pass default_tea_8082;
}

Send traffic

Using the external IP address and ports for the NGINX Service, we can send traffic to our coffee and tea applications.

If you have a DNS record allocated for cafe.example.com, you can send the request directly to that hostname, without needing to resolve.

Send requests to Gateway on different ports and observe which server the response comes from:

curl -i http://${GW_IP}:${GW_PORT_1}
text
Server address: 10.244.0.81:8080
Server name: coffee-5b9c74f9d9-brlsx
curl -i http://${GW_IP}:${GW_PORT_2}
text
Server address: 10.244.0.82:8080
Server name: tea-859766c68c-scndk

Requests sent to port ${GW_PORT_1} (listener coffee) are served by the coffee Service, and requests sent to port ${GW_PORT_2} (listener tea) are served by the tea Service.

Further Readings