wsproxy
A WebSocket proxy for TCP connections. Forward TCP traffic through WebSocket tunnels.
Architecture
TCP Client <---> ProxyClient <--WebSocket--> ProxyServer <---> TCP Server
- ProxyServer: Listens for WebSocket connections and forwards data to TCP targets. Supports routing different URL paths to different backends.
- ProxyClient: Listens for TCP connections and forwards data through WebSocket to the server.
Installation
Usage
Command Line
Server with a single default target:
Server with multiple routes:
Server with TLS (WSS):
Server with auto-generated self-signed certificate:
Client:
Client connecting to WSS server:
Client with self-signed certificate (insecure mode):
Client with custom CA certificate:
SSH ProxyCommand (Tunnel Mode)
The tunnel command connects stdin/stdout directly to a WebSocket server, making it perfect for SSH's ProxyCommand option:
Direct tunnel:
SSH config example:
Host myserver
ProxyCommand wsproxy tunnel --server wss://proxy:8443/ssh
User myuser
With self-signed certificate:
Host myserver
ProxyCommand wsproxy tunnel --server wss://proxy:8443/ssh --insecure
User myuser
Now ssh myserver will tunnel through the WebSocket proxy.
Daemon Mode
Run the server or client as a background daemon with automatic restart on failure:
Start a server daemon:
Start a server daemon with TLS:
Start a client daemon:
List running daemons:
Output:
ID PID ARGUMENTS
--------------------------------------------------
1 12345 server --listen 0.0.0.0:8080 --default-target 127.0.0.1:22
2 12346 client --listen 127.0.0.1:2222 --server ws://proxy-server:8080/ssh
Kill a daemon:
Daemons automatically restart with exponential backoff (1ms to 5 minutes) if the underlying process crashes.
Configuration File
Instead of command-line arguments, you can use a TOML configuration file with hot-reload support. When the config file changes, the server automatically picks up the new configuration without dropping active connections.
Start server with config file:
Example configuration file (server.toml):
= "0.0.0.0:8080"
= "localhost:22"
[]
= "ssh-server.internal:22"
= "db.example.com:5432"
= "127.0.0.1:6379"
[]
= "cert.pem"
= "key.pem"
# Or use: self_signed = true
Hostnames are resolved using DNS when the configuration is loaded.
Hot-reload behavior:
- Routes and default_target changes: Applied instantly. Existing connections continue uninterrupted; new connections use the updated routing.
- Listen address or TLS changes: Server automatically restarts. Existing connections continue until they complete naturally.
- Invalid configuration: If the config file has syntax errors or invalid values, the error is logged and the server continues running with the previous valid configuration. Existing connections are not affected.
Daemon mode with config:
Note: The --config flag cannot be combined with other server options (--listen, --route, --default-target, --tls-*).
Library
use ;
async
Example: Simple Chat with netcat
This example demonstrates a simple chat through the WebSocket proxy using nc (netcat).
Terminal 1 - Start a TCP listener (the "chat server"):
Terminal 2 - Start the proxy server and client as daemons:
Terminal 2 - Connect to the proxy:
Now you can type messages in Terminal 2 and they will appear in Terminal 1 (and vice versa). The data flows:
Terminal 2 (nc) -> ProxyClient (:2222) -> WebSocket -> ProxyServer (:8080) -> Terminal 1 (nc :9000)
Clean up - kill the daemons:
License
MIT License - see LICENSE for details.