Encrypt connections

You should always secure WebSocket connections with TLS (Transport Layer Security).

TLS vs. SSL

TLS is sometimes referred to as SSL (Secure Sockets Layer). SSL was an earlier encryption protocol; the name stuck.

The wss protocol is to ws what https is to http.

Secure WebSocket connections require certificates just like HTTPS.

Configure the TLS context securely

The examples below demonstrate the ssl argument with a TLS certificate shared between the client and the server. This is a simplistic setup.

Please review the advice and security considerations in the documentation of the ssl module to configure the TLS context appropriately.

Servers

In a typical deployment, the server is behind a reverse proxy that terminates TLS. The client connects to the reverse proxy with TLS and the reverse proxy connects to the server without TLS.

In that case, you don’t need to configure TLS in websockets.

If needed in your setup, you can terminate TLS in the server.

In the example below, serve() is configured to receive secure connections. Before running this server, download localhost.pem and save it in the same directory as server.py.

server.py
#!/usr/bin/env python

import asyncio
import pathlib
import ssl

from websockets.asyncio.server import serve

async def hello(websocket):
    name = await websocket.recv()
    print(f"<<< {name}")

    greeting = f"Hello {name}!"

    await websocket.send(greeting)
    print(f">>> {greeting}")

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
ssl_context.load_cert_chain(localhost_pem)

async def main():
    async with serve(hello, "localhost", 8765, ssl=ssl_context) as server:
        await server.serve_forever()

if __name__ == "__main__":
    asyncio.run(main())

Receive both plain and TLS connections on the same port isn’t supported.

Clients

connect() enables TLS automatically when connecting to a wss://... URI.

This works out of the box when the TLS certificate of the server is valid, meaning it’s signed by a certificate authority that your Python installation trusts.

In the example above, since the server uses a self-signed certificate, the client needs to be configured to trust the certificate. Here’s how to do so.

client.py
#!/usr/bin/env python

import pathlib
import ssl

from websockets.sync.client import connect

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
ssl_context.load_verify_locations(localhost_pem)

def hello():
    uri = "wss://localhost:8765"
    with connect(uri, ssl=ssl_context) as websocket:
        name = input("What's your name? ")

        websocket.send(name)
        print(f">>> {name}")

        greeting = websocket.recv()
        print(f"<<< {greeting}")

if __name__ == "__main__":
    hello()