Docs
Ingress ControllerManage traffic and APIsTraffic ManagementProxy WebSocket Connections

Proxy WebSocket Connections

Configure APISIX or API7 Ingress Controller to proxy WebSocket connections with HTTPRoute or ApisixRoute resources.

Applies to:API7 Ingress Controller (drives API7 Gateway)APISIX Ingress Controller (drives Apache APISIX)

Goal

Enable the gateway to proxy WebSocket connections to a backend Service using a Gateway API HTTPRoute or an APISIX CRD route.

Before you begin

  • Complete Set Up Ingress Controller and Gateway.
  • Install websocat to verify the WebSocket connection.
  • You have kubectl configured against the cluster used in the setup guide.
  • Choose a free local port for the gateway port-forward. The examples use 9080.

Set the variables this guide uses:

export UPSTREAM_WS_PORT="8080"
export UPSTREAM_APP_PROTOCOL="kubernetes.io/ws"
export WEBSOCKET_PATH="/.ws"
export GATEWAY_SERVICE_NAME="apisix-gateway"   # your gateway's Service name in namespace aic
export GATEWAY_HTTP_PORT="80"
export FORWARD_PORT="9080"

Steps

Step 1: Deploy the example WebSocket upstream

Create a manifest for the WebSocket echo server in the aic namespace. The server exposes the /.ws endpoint.

ws-echo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: aic
  name: websocket-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: websocket-server
  template:
    metadata:
      labels:
        app: websocket-server
    spec:
      containers:
      - name: echo-server
        image: jmalloc/echo-server
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  namespace: aic
  name: websocket-server
spec:
  selector:
    app: websocket-server
  ports:
  - name: ws
    port: 8080
    targetPort: 8080
    protocol: TCP
    appProtocol: kubernetes.io/ws
  type: ClusterIP

Apply the manifest and wait for the Pod to become ready:

kubectl apply -f ws-echo.yaml
kubectl wait --for=condition=ready pod -l app=websocket-server -n aic --timeout=120s

Step 2: Create the WebSocket route

Create a route that matches the WebSocket path and forwards to the example service:

ws-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: aic
  name: ws-route
spec:
  parentRefs:
  - name: apisix
  rules:
  - matches:
    - path:
        type: Exact
        value: /.ws
    backendRefs:
    - name: websocket-server
      port: 8080

HTTPRoute has no route-level WebSocket field. The Ingress Controller reads appProtocol from the referenced Service port and enables the protocol upgrade on the generated route.

Apply the manifest:

kubectl apply -f ws-route.yaml

Validate

Forward the gateway HTTP port to your local machine:

kubectl port-forward -n aic "svc/${GATEWAY_SERVICE_NAME}" "${FORWARD_PORT}:${GATEWAY_HTTP_PORT}" &

Establish a WebSocket connection through the route and send a test message:

websocat "ws://127.0.0.1:${FORWARD_PORT}${WEBSOCKET_PATH}"

Type hello and press Enter. Expected output:

Request served by 1cd244052136
hello
hello

The server echoes the message back. You can continue to send more messages; the server echoes each one. This confirms the bidirectional connection is successful and persistent.

Roll back / Clean up

Delete the manifests created in this guide:

kubectl delete -f ws-route.yaml
kubectl delete -f ws-echo.yaml

Stop the local port-forward process if it is still running:

kill %1 2>/dev/null || true

Troubleshoot

SymptomCauseFix
websocat returns 200 OK instead of 101 Switching Protocols.The backend Service does not declare the correct appProtocol, or the ApisixRoute websocket field is false.Verify the Service port has appProtocol: kubernetes.io/ws (or wss) for HTTPRoute, or websocket: true for ApisixRoute.
websocat cannot connect.The route is not accepted or the port-forward is not running.Check kubectl get httproute ws-route -n aic or kubectl get apisixroute ws-route -n aic, and confirm GATEWAY_SERVICE_NAME and FORWARD_PORT.
The echo server stops responding.The backend Pod or gateway worker was replaced, or the connection was closed.Open a new websocat connection after any endpoint change.