TCPRoute
Learn how to configure a TCPRoute to establish a TCP connection between NGINX Gateway Fabric and the backend applications.
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.
ImportantTCPRoute 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.
CautionAs 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 theedgeversion of NGINX Gateway Fabric, you can replace the version inrefwithmain, for exampleref=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.
- Install NGINX Gateway Fabric with experimental features enabled.
Create two simple applications coffee and tea by copying and pasting the following block into your terminal:
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
EOFThis creates two Services and Deployments for coffee and tea applications. Run the following command to verify the resources were created:
kubectl get pods,svcNAME 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 3m1sCreate a Gateway with two TCP listeners:
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
EOFThis 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 gatewayVerify the status is Accepted:
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: ProgrammedSave the public IP address and port(s) of the Gateway into shell variables:
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:
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
EOFThis configuration creates two TCPRoutes:
tcp-coffeeattaches to the Gateway listener named coffee on port 81 and forwards TCP connections to the coffee application.tcp-teaattaches 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.ioYou should see a similar status for both TCPRoutes tcp-coffee and tcp-tea:
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: defaultNext, verify that the TCPRoutes are configured by inspecting the NGINX configuration:
kubectl exec -it deployments/gateway-nginx -- nginx -TThe NGINX configuration should look something like:
server {
listen 81;
listen [::]:81;
proxy_pass default_coffee_8081;
}
server {
listen 82;
listen [::]:82;
proxy_pass default_tea_8082;
}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 forcafe.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}Server address: 10.244.0.81:8080
Server name: coffee-5b9c74f9d9-brlsxcurl -i http://${GW_IP}:${GW_PORT_2}Server address: 10.244.0.82:8080
Server name: tea-859766c68c-scndkRequests 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.