wstunnel: tunnelling TCP, UDP and SOCKS5 over WebSocket, HTTP2 or WebTransport
Tunnel all your traffic over Websocket or HTTP2 - Bypass firewalls/DPI - Static binary available
At a glance
- What is it?
- wstunnel is a Rust client and server that wrap arbitrary traffic in WebSocket, HTTP2 or WebTransport frames so it survives firewalls and proxies that only allow HTTP. It is a tunnelling primitive, not a VPN, and the README recommends WebSocket if you are unsure which transport to use.
- Who is it for?
- Adopt wstunnel when you control both ends and the path in between only permits HTTP-shaped traffic: a static binary on each side, a -L or -R tunnel definition, and the demo server to confirm the path works before you commit. Do not adopt it as a general-purpose VPN replacement.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 26 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- erebe/wstunnel7,197 ★ · +144
| Repository | 2026-09-23 | 2026-11-13 |
|---|---|---|
| erebe/wstunnel | 7.1k | 7.2k |
144 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
What wstunnel is for, and who ends up using it
The README starts from a plain observation: on a public network you are usually behind a firewall or proxy whose job is to restrict you to a subset of protocols, and HTTP is the one that is allowed almost everywhere. wstunnel takes whatever traffic you have and carries it inside the WebSocket protocol, which the README notes is compatible with HTTP, so the traffic looks like something the network already permits. That is the whole pitch. It is not a mesh network, not a key exchange system, and not a way to hide from your own endpoint.
The audience is narrower than the tagline suggests. You need a host you can reach from the restricted network and a host you can run the client on, and you need to be willing to define each tunnel by hand. The README lists what that buys you: static forward and reverse tunnelling over TCP, UDP, Unix sockets and stdio; dynamic tunnelling through a SOCKS5 proxy, an HTTP proxy or a transparent proxy; support for using an HTTP proxy as the gateway when you are behind one; proxy protocol support; TLS with certificate auto-reload; mTLS; IPv6. Reverse tunnelling is the part that changes the shape of a deployment. The client can expose a service that lives on the client side to whoever connects to the server, which is how you reach a machine that has no inbound reachability at all.
The project is a Rust rewrite. The README states that v7.0.0 was a complete rewrite and is not compatible with earlier versions, and that the previous Haskell code lives on a separate branch. The author gives the reason plainly: maintaining the Haskell ecosystem had become hard, and the rewrite also brought back an Armv7 build after a GHC release dropped support for it. If you are searching for an older wstunnel and find Haskell-era instructions, they do not apply.
How the client and server actually move bytes
One binary runs as `wstunnel client` or `wstunnel server`. The server listens and the client dials out to it; `--connection-min-idle` keeps a pool of connections to the server open to speed up new tunnels. The address argument decides the transport: ws:// or wss:// for WebSocket, http:// or https:// for HTTP2, wts:// for WebTransport. The README recommends WebSocket if you are unsure, and the feature list calls it the more performant transport.
The server detects by itself whether a request is websocket or http2, so you do not need to specify it.
WebTransport is always TLS. The server serves it when bound with wts://0.0.0.0:8080, which is equivalent to wss://0.0.0.0:8080 --enable-webtransport; the TCP listener still serves websocket and http2.
On the wire, each tunnel is described by a local-to-remote or remote-to-local specification. The client accepts -L and -R repeatedly, so a single client process can hold several tunnels at once.
Installing wstunnel and running a first tunnel
There is no package manager step in the README. It points at the releases page for standalone binaries and describes them as something you copy where you want it, which is the intended install path on a machine where you have no build toolchain. The repository also contains a Dockerfile for a container image, built from a Rust builder stage and finished on debian:trixie-slim, with the binary at /home/app/wstunnel, SERVER_PROTOCOL defaulting to wss, SERVER_LISTEN to [::], SERVER_PORT to 8080, and port 8080 exposed.
Before building anything of your own, the README offers a demo server so you can confirm the path through your network works at all. The client listens locally on port 4443 and forwards to 10.43.0.11 on port 443 through wss://ws.erebe.dev, with the tunnel password given as demo and the TLS SNI overridden to google.fr:
wstunnel client -L 'tcp://4443:10.43.0.11:443' -P demo --tls-sni-override=google.fr wss://ws.erebe.devIn a second terminal, the README's curl against that local port should return the greeting Memento mori:
curl -k https://localhost:4443If that returns, the transport reaches the server and the failure is somewhere in your own tunnel definition. If it hangs, the problem is the path, not the tunnel, and the transport warnings above are the place to look. From there, a real tunnel follows the same shape. On your remote host, start the server:
wstunnel server wss://[::]:8080For a dynamic tunnel rather than a fixed one, the client can expose a SOCKS5 listener and resolve destinations on demand. The README's example binds it to the loopback interface on port 8888 and keeps a pool of idle connections:
wstunnel client -L socks5://127.0.0.1:8888 --connection-min-idle 5 wss://myRemoteHost:8080Where wstunnel is the wrong tool
The first limitation is that wstunnel is not a VPN. There is no virtual interface, no routing table change, no address assignment. Every destination you want to reach has to appear in a -L or -R specification, or be resolved dynamically through the SOCKS5 or HTTP proxy listener. If your mental model is "connect and then everything routes through the tunnel", wstunnel does not do that, and you would be looking at the transparent proxy mode or a different class of software entirely.
The second is that the transport choice can silently disqualify itself. WebSocket is the README's recommended default when unsure, and it is also described as the more performant of the three in the feature list, which makes the other two worth choosing only when you have a specific reason.
The third is compatibility. The rewrite at v7.0.0 broke the protocol, so a client and server on opposite sides of that line will not talk to each other. That matters for anyone running a long-lived server and updating clients piecemeal. The practical rule is to move both ends together.
Finally, the README's table of contents includes a benchmark section, and its notes say a single connection can now saturate a gigabit ethernet card. mTLS is documented in a separate file, docs/using_mtls.md, rather than in the main README, which means the security configuration most people would want is one link away from the page they land on.
How wstunnel differs from a SOCKS proxy or a WireGuard tunnel
The closest comparison is Shadowsocks, and the difference is structural rather than a matter of tuning. Shadowsocks is a proxy protocol: a client speaks to a local SOCKS5 interface, the Shadowsocks process encrypts and forwards to a server that decrypts and connects onward. wstunnel also offers a SOCKS5 listener, and that is where the resemblance stops. The bytes between the wstunnel client and server are carried inside WebSocket, HTTP2 or WebTransport frames, which is what lets them pass equipment that has decided HTTP is acceptable. Shadowsocks traffic is not shaped like HTTP, which is exactly why it needs its own obfuscation story when DPI is aggressive.
WireGuard is a different layer again, and wstunnel's README includes a 'Proxy Wireguard traffic' example, which is a hint about how the two are meant to combine rather than compete. WireGuard gives you an encrypted interface and a routing decision for every packet; wstunnel gives you a stream that survives a restrictive path. Running WireGuard's UDP inside a wstunnel UDP tunnel is the composition the README's Wireguard example points to, and it is the reason someone would pick wstunnel over a plain proxy: the outer layer is the part that gets through.
Against a plain SOCKS5 proxy, the difference is reachability in the other direction. A SOCKS5 proxy is something you connect to. wstunnel's reverse mode is something that connects to you, which is what you need when the machine holding the service cannot accept inbound connections. That single capability is often the actual reason to use it.
Editorial conclusion
Adopt wstunnel when you control both ends and the path in between only permits HTTP-shaped traffic: a static binary on each side, a -L or -R tunnel definition, and the demo server to confirm the path works before you commit. Do not adopt it as a general-purpose VPN replacement. Verify first that the transport you picked works end to end, and use WebSocket if you are unsure, as the README recommends.
Frequently asked questions
What is wstunnel?
It is a client and server that tunnel arbitrary traffic over WebSocket, HTTP2 or WebTransport, which the README describes as a way to bypass firewalls and proxies that only allow HTTP. It supports static forward and reverse tunnelling over TCP, UDP, Unix sockets and stdio, plus dynamic tunnelling through SOCKS5, HTTP proxy and transparent proxy modes.
What is the wstunnel protocol?
The client dials the server over one of three transports selected by the address scheme: ws:// or wss:// for WebSocket, http:// or https:// for HTTP2, and wts:// for WebTransport. Individual tunnels are declared with -L or -R specifications, and --connection-min-idle can keep a pool of connections to the server open.
Is wstunnel safe?
The answer depends on how you configure it, and the README has a section on how to secure access to your wstunnel server. It supports TLS with certificate auto-reload, an embedded self-signed certificate or your own, and mTLS documented in docs/using_mtls.md. WebTransport always uses TLS because QUIC mandates TLS 1.3, while ws:// and http:// are cleartext.
wstunnel vs shadowsocks: what is the difference?
Shadowsocks is a proxy protocol whose traffic is not shaped like HTTP, while wstunnel carries its streams inside WebSocket, HTTP2 or WebTransport frames so they pass equipment that permits HTTP. wstunnel also offers a SOCKS5 listener, but the framing layer is the point of the project.
What are wstunnel alternatives?
The README includes an example for proxying Wireguard traffic, and it notes the original inspiration was an npm package also called wstunnel, which the author rewrote in Rust to avoid installing Node.js.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/erebe-wstunnel)Star history chart for your README
[](https://hysenlabs.com/projects/erebe-wstunnel)Was this useful?