All Products
Search
Document Center

Alibaba Cloud Service Mesh:Access services using the WebSocket protocol in ASM

Last Updated:Mar 10, 2026

Alibaba Cloud Service Mesh (ASM) supports WebSocket (RFC 6455) through Istio sidecar proxies without additional configuration. This guide walks you through deploying a sample WebSocket client and server, then establishing WebSocket connections over HTTP/1.1 and HTTP/2.

How WebSocket works in ASM

A WebSocket connection starts as a standard HTTP request with an Upgrade header. After the client and server negotiate the upgrade, the connection switches to full-duplex, two-way communication over a single persistent connection.

Istio does not recognize the WebSocket protocol directly. Instead, Envoy sidecar proxies treat WebSocket traffic as TCP byte streams after the initial HTTP Upgrade handshake. This means:

  • Envoy generates a single access log entry per WebSocket connection, written only after the connection closes.

  • The log entry does not include details of individual messages sent over the connection.

For more information, see HTTP upgrades, HTTP connection manager, and Protocol Selection.

HTTP/1.1 vs. HTTP/2

ProtocolBehavior
HTTP/1.1Each connection handles one request. The connection closes after the response.
HTTP/2Multiple requests run in parallel over a single connection. A slow request does not block others.

Prerequisites

Before you begin, make sure that you have:

Deploy a WebSocket server and client

Step 1: Connect to the ACK cluster

Connect to the ACK cluster by using kubectl. For more information, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.

Step 2: Deploy the WebSocket server

This example uses the Python WebSocket server provided by the WebSocket community. For configuration details, see Deploy to Kubernetes.

  1. Create a file named websockets-server.yaml with the following content:

    apiVersion: v1
    kind: Service
    metadata:
      name: websockets-server
      labels:
        app: websockets-server
    spec:
      type: ClusterIP
      ports:
        - port: 8080
          targetPort: 80
          name: http-websocket
      selector:
        app: websockets-server
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: websockets-server
      labels:
        app: websockets-server
    spec:
      selector:
        matchLabels:
          app: websockets-server
      template:
        metadata:
          labels:
            app: websockets-server
        spec:
          containers:
          - name: websockets-test
            image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/istio-websockets-test:1.0
            ports:
            - containerPort: 80
  2. Apply the manifest to the default namespace:

    kubectl apply -f websockets-server.yaml -n default

Step 3: Deploy the WebSocket client

The client image is built from a Dockerfile that installs the websockets Python package:

FROM python:3.9-alpine
RUN pip3 install websockets
  1. Create a file named websockets-client.yaml with the following content:

    apiVersion: v1
    kind: Service
    metadata:
      name: websockets-client
      labels:
        app: websockets-client
    spec:
      type: ClusterIP
      ports:
        - port: 8080
          targetPort: 80
          name: http-websockets-client
      selector:
        app: websockets-client
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: websockets-client-sleep
      labels:
        app: websockets-client
    spec:
      selector:
        matchLabels:
          app: websockets-client
      template:
        metadata:
          labels:
            app: websockets-client
        spec:
          containers:
          - name: websockets-client
            image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/istio-websockets-client-test:1.0
            command: ["sleep", "14d"]
  2. Apply the manifest to the default namespace:

    kubectl apply -f websockets-client.yaml -n default

Establish WebSocket connections over HTTP/1.1

Because Envoy treats WebSocket connections as TCP byte streams, sidecar proxies record only one access log entry per connection. The entry is written after the connection closes and does not contain per-message details.

Connect to the WebSocket server

  1. Open a shell in the client pod. Use either of the following methods: Option A: ACK console Option B: kubectl

    1. Log on to the ACK console. In the left-side navigation pane, click Clusters.

    2. On the Clusters page, click the name of your cluster. In the left-side pane, choose Workloads > Pods.

    3. On the Pods page, find websockets-client and click Terminal in the Actions column. Then select websockets-client.

    kubectl exec -it -n <namespace> <websockets-client-sleep-pod> -c websockets-client -- sh
  2. Connect to the WebSocket server. Replace <namespace> with your target namespace (for example, default): Expected output:

    python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
    Connected to ws://websockets-server.default.svc.cluster.local:8080.
  3. Send test messages. Type hello and world, then close the connection:

    > hello
    < hello
    > world
    < world
    Connection closed: 1000 (OK).

Verify the sidecar proxy logs

  1. Client sidecar log: On the Pods page, click the client pod name. Click the Logs tab and select istio-proxy from the Container drop-down list. The log shows HTTP/1.1 as the protocol:

    {...."upstream_host":"10.208.0.105:80","bytes_sent":23,"protocol":"HTTP/1.1",....}
  2. Server sidecar log: On the Pods page, click the server pod name. Click the Logs tab and select istio-proxy from the Container drop-down list. The log also shows HTTP/1.1:

    {...."downstream_local_address":"10.208.0.105:80","upstream_local_address":"127.0.**.**:53983","protocol":"HTTP/1.1",....}

Establish WebSocket connections over HTTP/2

WebSocket does not work natively with HTTP/2. However, Envoy supports tunneling WebSocket over HTTP/2 connections, so all communication within the ASM instance can use HTTP/2.

Important

For Istio versions earlier than 1.12, upgrading HTTP/1.1 connections to HTTP/2 for WebSocket traffic returns HTTP status code 503. In this case, set h2UpgradePolicy to DO_NOT_UPGRADE in the DestinationRule to keep connections on HTTP/1.1:

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  labels:
    provider: asm
  name: websockets-server
spec:
  host: websockets-server
  trafficPolicy:
    connectionPool:
      http:
        h2UpgradePolicy: DO_NOT_UPGRADE

For Istio 1.12 or later, complete the following steps to enable WebSocket over HTTP/2.

Step 1: Create a DestinationRule

  1. Log on to the ASM console.

  2. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  3. On the Mesh Management page, find the target ASM instance. Click the instance name or click Manage in the Actions column.

  4. In the left-side navigation pane, choose Traffic Management Center > DestinationRule. On the page that appears, click Create from YAML.

  5. On the Create page, select default from the Namespace drop-down list. Paste the following YAML into the code editor and click Create: Setting h2UpgradePolicy to UPGRADE enables HTTP/2 for the WebSocket server.

    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      labels:
        provider: asm
      name: websockets-server
    spec:
      host: websockets-server
      trafficPolicy:
        connectionPool:
          http:
            h2UpgradePolicy: UPGRADE

Step 2: Create an EnvoyFilter

Enable the HTTP/2 CONNECT method on the server-side sidecar by setting allow_connect to true. This allows Envoy to tunnel WebSocket connections over HTTP/2.

  1. Log on to the ASM console.

  2. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  3. On the Mesh Management page, find the target ASM instance. Click the instance name or click Manage in the Actions column.

  4. In the left-side navigation pane, choose Plugin Extension Center > Market Place.

  5. On the Market Place page, click Template that sets the allow_connect parameter to true to allow updated protocol connections.

  6. On the Plugin Detail page, click the Plugin Config tab. In the Plugin Effective scope section, select Workload Scope and click Add workloads to effective scope.

  7. In the Add workloads to effective scope dialog box, set Namespace to default and Workload Type to Deployment. In the Select workloads section, select websockets-server, click the Add icon icon to move it to the selected section, and click OK.

  8. In the YAML code editor of the Plugin Config section, enter patch_context: SIDECAR_INBOUND. Turn on Plugin Switch and wait for the plug-in to activate.

After the plug-in is enabled, ASM automatically creates the following EnvoyFilter:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: h2-upgrade-wss
  labels:
    asm-system: 'true'
    provider: asm
spec:
  workloadSelector:
    labels:
      app: websockets-server
  configPatches:
  - applyTo: NETWORK_FILTER
    match:
      context: SIDECAR_INBOUND
      proxy:
        proxyVersion: '^1\.*.*'
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: MERGE
      value:
        typed_config:
          '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          http2_protocol_options:
            allow_connect: true

Step 3: Test the connection

  1. Connect to the WebSocket server from the client pod. Replace <namespace> with your target namespace (for example, default): Expected output:

    python3 -m websockets ws://websockets-server.<namespace>.svc.cluster.local:8080
    Connected to ws://websockets-server.default.svc.cluster.local:8080.
  2. Send test messages:

    > hello
    < hello
    > world
    < world
    Connection closed: 1000 (OK).

Verify the sidecar proxy logs

  1. Client sidecar log: The client still sends requests over HTTP/1.1:

    {...."authority":"websockets-server.default.svc.cluster.local:8080","upstream_service_time":null,"protocol":"HTTP/1.1",....}
  2. Server sidecar log: The server receives requests upgraded to HTTP/2: This confirms that the sidecar proxy tunneled the WebSocket connection over HTTP/2.

    {...."method":"GET","upstream_local_address":"127.0.**.**:34477","protocol":"HTTP/2",....}