Documentation / WebSocket Tunneling

WebSocket Tunneling

Full WebSocket support for real-time applications, Streamlit, Jupyter, and more

Overview

stunl natively supports WebSocket connections through HTTP tunnels. WebSocket upgrade requests are automatically detected and handled, enabling bidirectional real-time communication through your tunnel.

WebSocket Support Included

WebSocket support is included in Pro. Perfect for Streamlit, Jupyter notebooks, Socket.IO apps, and any real-time application. Start free.

How WebSocket Tunneling Works
  • 1. Client sends HTTP request with Upgrade: websocket header
  • 2. stunl detects the upgrade request and maintains persistent connection
  • 3. Bidirectional frames are forwarded between client and your local server
  • 4. Connection stays open until either side closes it

Quick Start

No special configuration needed! WebSocket connections work automatically through HTTP tunnels.

Expose a WebSocket server
# Your WebSocket server runs on port 8080
$ stunl -port 8080

  ● STUNL

  ╭── ◎ ── HTTP
  │   HTTPS    https://abc123.stunl.io
  │   HTTP     http://abc123.stunl.io
  │   Local    localhost:8080

# Connect via WebSocket:
wss://abc123.stunl.io
ws://abc123.stunl.io

Framework Examples

Streamlit

Expose Streamlit app
# Terminal 1: Start Streamlit
$ streamlit run app.py --server.port 8501

# Terminal 2: Create tunnel
$ stunl -port 8501 -id my-streamlit

# Share with your team:
https://my-streamlit.stunl.io

Jupyter Notebook

Expose Jupyter Notebook
# Terminal 1: Start Jupyter
$ jupyter notebook --port 8888 --NotebookApp.allow_origin='*'

# Terminal 2: Create tunnel
$ stunl -port 8888 -id my-jupyter

# Access remotely (use the token from Jupyter output):
https://my-jupyter.stunl.io/?token=xxx

Socket.IO (Node.js)

Socket.IO server and client
// server.js
const io = require('socket.io')(3000, {
  cors: { origin: '*' }
});

io.on('connection', (socket) => {
  console.log('Client connected');
  socket.on('message', (data) => {
    io.emit('message', data);
  });
});

// Start and tunnel
$ node server.js
$ stunl -port 3000 -id chat

// Client connection
const socket = io('https://chat.stunl.io');

FastAPI WebSockets

FastAPI WebSocket endpoint
# main.py
from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Echo: {data}")

# Start and tunnel
$ uvicorn main:app --port 8000
$ stunl -port 8000 -id api

# Connect to:
wss://api.stunl.io/ws

Multi-Port with WebSockets

When using multi-port tunneling, you can route WebSocket connections alongside HTTP traffic using path-based routing.

HTTP + WebSocket on same tunnel
# Frontend on 3000, WebSocket server on 3001
$ stunl -id myapp -ports "web:3000:http,ws:3001:http"

  ● STUNL

  ╭── ◎ ── HTTP web
  │   HTTPS    https://myapp.stunl.io
  │   Local    localhost:3000

  ╭── ◎ ── HTTP ws
  │   HTTPS    https://myapp.stunl.io/ws
  │   Local    localhost:3001

# Frontend: https://myapp.stunl.io
# WebSocket: wss://myapp.stunl.io/ws

Pro Features

Feature Pro
WebSocket support
Connection timeout Unlimited
Monthly bandwidth 25 GB

Tips & Best Practices

Use WSS (Secure WebSocket)

Always connect to wss:// URLs. stunl provides TLS termination automatically, ensuring encrypted connections.

Handle Reconnection

Implement reconnection logic in your WebSocket client. Network interruptions can drop connections, and your client should gracefully reconnect.

CORS Configuration

If your WebSocket server uses CORS, allow the stunl domain or use origin: '*' for development.

Ping/Pong Keepalive

stunl supports WebSocket ping/pong frames. Your server should respond to ping frames to keep connections alive through proxies and load balancers.

Troubleshooting

WebSocket connection fails immediately

Make sure you're using the correct protocol:

  • wss:// for HTTPS tunnels (recommended)
  • ws:// for HTTP tunnels

Connection drops after a few seconds

Some browsers close idle WebSocket connections. Implement ping/pong or heartbeat messages to keep the connection active.

Mixed content errors

If your page is served over HTTPS, you must use wss:// for WebSocket connections. Browsers block ws:// on HTTPS pages.

Next Steps