WebSocket Protocol
NullBore uses a WebSocket-based relay protocol inspired by bore and chisel. This page documents the wire protocol for client implementors.
Overview
┌─────────┐ HTTPS ┌──────────┐ Control WS ┌────────┐
│ Internet │────────────→│ Server │←────────────→│ Client │
│ Client │ │ (relay) │ Data WS │ │
└─────────┘ └──────────┘ └────────┘
↕
localhost:3000
Connection flow
- Client creates tunnel via
POST /v1/tunnels - Client opens control WebSocket:
GET /ws/control?tunnel_id={id} - Inbound HTTP request arrives at
/t/{slug}or{slug}.tunnel.nullbore.com - Server hijacks the inbound connection and reconstructs the HTTP request bytes
- Server sends notification on control WS:
{"type":"connection","id":"<uuid>"} - Client opens data WebSocket:
GET /ws/data?id=<uuid> - Server pipes the inbound connection ↔ data WebSocket bidirectionally
Control channel
GET /ws/control?tunnel_id={tunnel_id}
Authorization: Bearer nbk_your_key
The control channel is a long-lived WebSocket. The server sends JSON messages:
Connection notification
{"type": "connection", "id": "550e8400-e29b-41d4-a716-446655440000"}
Sent when a new inbound request arrives. The client must open a data WebSocket with this id within 10 seconds, or the connection is dropped.
Keepalive
The server sends WebSocket ping frames every 30 seconds. The client must respond with pong within 60 seconds or the connection is considered dead.
Data channel
GET /ws/data?id={connection_id}
The data channel is a short-lived WebSocket for a single connection. Once opened:
- Server writes the reconstructed HTTP request bytes (method, path, headers, body)
- Bidirectional
io.Copystreams bytes between the inbound client and the data WebSocket - When either side closes, the other side closes too
Data flows as raw WebSocket binary messages — no JSON wrapping, no framing.
WSNetConn adapter
The server wraps websocket.Conn as a standard net.Conn via a WSNetConn adapter. This allows using standard Go io.Copy for the relay, with proper Close, Read, and Write semantics.
Timeouts
| Timeout | Duration | Description |
|---|---|---|
| Pending connection | 10s | Time for client to open data WS after notification |
| Ping interval | 30s | Server sends ping on control channel |
| Pong timeout | 60s | Client must respond to ping |