Skip to main content

Version: latest

Configure TCP/UDP Proxying

API7 Gateway can proxy Layer 4 (TCP/UDP) traffic in addition to HTTP traffic. This enables you to use the gateway as a unified entry point for non-HTTP protocols such as MySQL, Redis, MQTT, and custom TCP services.

This guide walks through configuring a TCP proxy to a MySQL database as an example. The same approach applies to any TCP or UDP service.

Prerequisites

  • An API7 Enterprise instance is running.
  • A Gateway Group is created and a Gateway instance is running.
  • A token from the Dashboard.
  • A MySQL client is installed if you want to validate the sample TCP proxy with mysql.

Start a Sample TCP Upstream

Start the same sample MySQL server used in the API7 Enterprise TCP proxy best-practice guide:

docker run -d \
--name mysql \
--network host \
-e MYSQL_ROOT_PASSWORD=password \
mysql:8.4 \
mysqld --mysql-native-password=ON

The examples below assume the gateway can reach the Docker host at host.docker.internal. If your environment uses a different host address, replace host.docker.internal with that address.

Ensure a Stream Proxy Port Is Available

Before traffic can reach a stream route, the gateway must already be listening on a TCP or UDP port for stream traffic.

Admin API and ADC can create stream services and stream routes, but they do not create or expose the gateway listener itself. If your API7 Enterprise deployment already provides an L4 listener, reuse that port in server_port. If not, add one in the gateway runtime configuration and redeploy or restart the gateway so the new listener is exposed.

If you manage the gateway runtime directly, add the port to config.yaml as follows:

config.yaml
apisix:
stream_proxy:
only: false
tcp:
- 2000

If the gateway runs in Docker, also publish the same port from the container to the host. For example, recreate or redeploy the gateway container with -p 2000:2000.

For Kubernetes deployments, add the stream proxy ports to your Helm values, ensure the Service exposes them, and redeploy the gateway.

Create a Stream Service

Once a stream listener is available on the gateway, create a service with type stream and configure the upstream.

curl -k "https://localhost:7443/apisix/admin/services/mysql-service?gateway_group_id={group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "mysql-service",
"type": "stream",
"upstream": {
"scheme": "tcp",
"nodes": [
{
"host": "host.docker.internal",
"port": 3306,
"weight": 100
}
]
}
}'

Create a Stream Route

Create a stream route that matches traffic on the stream proxy port and forwards it to the upstream.

curl -k "https://localhost:7443/apisix/admin/stream_routes/mysql-route?gateway_group_id={group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "mysql-route",
"server_port": 2000,
"service_id": "mysql-service"
}'

server_port must match an existing gateway stream listener configured under stream_proxy.tcp or stream_proxy.udp. In the Admin API example, service_id references the stream service that contains the upstream configuration.

For ADC workflows, define stream routes under the parent service. To validate the examples end to end, make sure the same stream port is configured on the gateway and exposed to clients by your deployment.

Validate the Configuration

After the gateway has been redeployed or restarted with the stream listener enabled and exposed, test the TCP proxy by connecting to the gateway's stream proxy port:

# MySQL example
mysql -h 127.0.0.1 -P 2000 -u root -p

If the connection succeeds and you can interact with the MySQL server, the stream route is working correctly.

For a generic TCP test:

# Using netcat
nc -zv 127.0.0.1 2000

Add Stream Plugins

Stream routes support a limited set of plugins. For example, you can use limit-conn to add connection rate limiting:

curl -k "https://localhost:7443/apisix/admin/stream_routes/mysql-route?gateway_group_id={group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "mysql-route",
"server_port": 2000,
"service_id": "mysql-service",
"plugins": {
"limit-conn": {
"conn": 100,
"burst": 50,
"default_conn_delay": 0.1,
"key": "remote_addr",
"key_type": "var"
}
}
}'

PUT replaces the entire stream route, so re-send the existing fields (name, server_port, service_id) along with the new plugins block.

Configure TLS for Stream Routes

To proxy TLS-encrypted TCP connections with SNI-based routing:

  1. Enable a TLS stream proxy port:

    config.yaml
     apisix:
    stream_proxy:
    tcp:
    - addr: 9443
    tls: true
  2. Create stream routes with the sni field to route based on the client's TLS Server Name Indication.

Next Steps

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation