Proxy WebSocket Connections
WebSocket provides bidirectional communication between a client and server over a long-lived connection. When the Ingress Controller translates a route, the generated gateway route must allow the HTTP connection to upgrade to WebSocket.
The gateway can proxy WebSocket backends configured through HTTPRoute, ApisixRoute, or Ingress. To limit concurrent WebSocket connections, see the limit-conn plugin.
Prerequisites
- Complete Set Up Ingress Controller and Gateway.
- Install websocat to verify the WebSocket connection.
Enable WebSocket
Where you enable WebSocket depends on the route resource:
| Resource | Configuration |
|---|---|
| HTTPRoute | Set the backend Service port appProtocol to kubernetes.io/ws or kubernetes.io/wss. HTTPRoute has no route-level alternative. |
| ApisixRoute | Set spec.http[].websocket to true, or use the Service port appProtocol. |
| Ingress | Set the k8s.apisix.apache.org/enable-websocket annotation to true, or use the Service port appProtocol. |
The examples below configure HTTPRoute and ApisixRoute. If you cannot modify the backend Service, use the ApisixRoute field or Ingress annotation instead of HTTPRoute.
Start an Example Upstream Service
Create a Kubernetes manifest file for the deployment and service of a WebSocket server. The server has a WebSocket endpoint at /.ws that echoes back any message received.
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
The HTTPRoute example requires this appProtocol setting. Without it, the gateway treats the WebSocket handshake as an ordinary HTTP request. A successful HTTP/1.1 WebSocket handshake returns 101 Switching Protocols; a normal response such as 200 OK means the connection was not upgraded. The same setting can also enable WebSocket for Ingress and ApisixRoute. The kubernetes.io/ws value selects HTTP for the upstream connection; use kubernetes.io/wss for an upstream that accepts TLS connections. See Detect Upstream Protocol with appProtocol for the complete protocol mapping.
Apply the configuration to your cluster:
kubectl apply -f ws-echo.yaml
Create a Route
Choose HTTPRoute or ApisixRoute for the example service:
- Gateway API
- APISIX CRD
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.
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: ws-route
spec:
ingressClassName: apisix
http:
- name: ws-route
match:
paths:
- /.ws
websocket: true
backends:
- serviceName: websocket-server
servicePort: 8080
The websocket: true field is sufficient for ApisixRoute even when the Service port does not declare appProtocol. In this example, either setting enables the protocol upgrade.
Apply the configuration to your cluster:
kubectl apply -f ws-route.yaml
Verify Connections
For the APISIX local evaluation setup, expose the gateway Service on your local machine. For an API7 installation, substitute the gateway Service generated by API7 Dashboard.
kubectl port-forward svc/apisix-gateway 9080:80 &
Establish a connection with the WebSocket server through the route:
websocat "ws://127.0.0.1:9080/.ws"
Send a "hello" message in the terminal. You should see the WebSocket server echoes back the same message:
Request served by 1cd244052136
hello
hello
You can continue to send more messages and the WebSocket server will echo back any message you sent. This shows the bidirectional connection is successful and persistent.
Update or Remove a Route
Changing the backend Service endpoints affects new WebSocket connections. An established connection remains attached to its selected backend until the connection ends, so open a new connection to verify an endpoint change.
Deleting the route prevents new matching connections but does not close connections that have already completed the WebSocket upgrade. Those connections remain open until the client, backend, or gateway closes them.