Proxy TCP Traffic by Port
This guide explains how to define routing rules for TCP traffic based on the incoming port through the Ingress Controller. A MySQL server is used as the example upstream.
Prerequisites
- Complete Set Up Ingress Controller and Gateway.
- Install MySQL Shell to initiate connections with MySQL server.
Start an Example Upstream Service
Create a Kubernetes manifest file for an example MySQL upstream service with the root password my-secret-pw:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
namespace: aic
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:9.4
env:
- name: MYSQL_ROOT_PASSWORD
value: "my-secret-pw"
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumes:
- name: mysql-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: aic
spec:
selector:
app: mysql
ports:
- name: mysql
port: 3306
targetPort: 3306
Apply the configuration to your cluster:
kubectl apply -f mysql.yaml
Enable Gateway Stream Proxy
Upgrade your gateway to enable stream mode and set TCP port 9100:
- APISIX Gateway
- API7 Gateway
helm upgrade -n aic apisix apisix/apisix \
--set ... \ # add other parameters
--set "service.stream.enabled=true" \
--set "service.stream.tcp[0]=9100"
helm upgrade -n aic api7-ee-3-gateway api7/gateway \
--set ... \ # add other parameters
--set "gateway.stream.enabled=true" \
--set "gateway.stream.only=false" \
--set "gateway.stream.tcp[0]=9100"
Configure TCP Routing
In this section, you will configure a route that listens for TCP traffic on port 9100.
- Gateway API
- APISIX CRD
Update your Gateway manifest file to define a listener for TCP traffic:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: aic
name: apisix
spec:
gatewayClassName: apisix
listeners:
- name: http
protocol: HTTP
port: 80
- name: tcp
protocol: TCP
port: 9100
allowedRoutes:
kinds:
- kind: TCPRoute
infrastructure:
parametersRef:
group: apisix.apache.org
kind: GatewayProxy
name: apisix-config
Create a Kubernetes manifest for a TCPRoute:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: stream-route-mysql
namespace: aic
spec:
parentRefs:
- name: apisix
sectionName: tcp
rules:
- backendRefs:
- name: mysql
port: 3306
Apply the configuration to your cluster:
kubectl apply -f gateway.yaml -f tcp-route.yaml
Create a Kubernetes manifest file for a stream route:
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: stream-route-mysql
namespace: aic
spec:
ingressClassName: apisix
stream:
- name: stream-route-mysql
protocol: TCP
match:
ingressPort: 9100
backend:
serviceName: mysql
servicePort: 3306
Apply the configuration to your cluster:
kubectl apply -f tcp-route.yaml
Verify
Expose the gateway’s service port to your local machine:
# replace with your gateway’s service name
kubectl port-forward svc/<gateway-service-name> 9100:9100 &
Connect with the MySQL server as root and key in the password my-secret-pw once prompted:
mysql --host=127.0.0.1 --port=9100 -u root -p
If successful, you should see a welcome text similar to the following:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 9.4.0 MySQL Community Server - GPL
Copyright (c) 2000, 2025, Oracle and/or its affiliates.