Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Wormhole (woho)

A lightweight reverse tunnel, written in Rust, for exposing a local service to the internet. It uses QUIC for the control/data channel between client and server, and a raw TCP + httparse gateway on the server side that routes incoming HTTP traffic by Host header — either to an active QUIC tunnel (dynamic) or to a fixed backend address (static).

Status: early / experimental. The core tunneling path works, but hardening (TLS verification, rate limiting, input limits) is still in progress — see Security Notice below before exposing this to untrusted traffic.

How it works

There are two binaries:

  • woho-server — runs on your VPS / public server. It listens on two ports:
    • a QUIC port, where woho clients authenticate and register a subdomain;
    • an HTTP port, where public traffic arrives and gets routed by Host header.
  • woho — runs next to the local app you want to expose (e.g. a dev server on localhost:3000). It authenticates to woho-server over QUIC and keeps the connection open so the server can push incoming requests through it.
flowchart LR
    Internet -->|HTTP request, Host: dev.example.com| Gateway[woho-server: HTTP Gateway]
    Gateway -->|subdomain registered?| Registry[(Session Registry)]
    Registry -->|yes: dynamic route| QUICConn[QUIC Connection]
    Registry -->|no: check static_routes| Static[Static upstream, e.g. 127.0.0.1:9000]
    QUICConn <-->|bidirectional stream| Client[woho client]
    Client <--> LocalApp[Your local app, e.g. 127.0.0.1:3000]
Loading

Dynamic routes are created on the fly: when a woho client authenticates successfully, the server registers its Connection under the assigned subdomain. Every subsequent HTTP request whose Host matches that subdomain opens a new bidirectional QUIC stream to that client, which the client forwards to your local port.

Static routes are fixed mappings defined in the server config (subdomain -> upstream), useful for backends that live permanently on the same machine as woho-server and don't need a tunnel at all.

Getting started

Build

cargo build --release
# binaries end up in target/release/woho and target/release/woho-server

1. Server setup

Generate (or bring your own) TLS certificate for the QUIC listener:

openssl req -x509 -newkey rsa:2048 -nodes \
  -keyout key.pem -out cert.pem -days 365 -subj "/CN=localhost"

Create woho-server.toml:

[server]
listen_quic = "0.0.0.0:4433"
listen_http = "0.0.0.0:8080"
domain_suffix = "yourdomain.com"

[tls_config]
cert_path = "cert.pem"
key_path = "key.pem"

# Fixed mappings — always available, no client/tunnel required
[[static_routes]]
subdomain = "status"
upstream = "127.0.0.1:9090"

[[static_routes]]
subdomain = "internal-api"
upstream = "127.0.0.1:9000"

# Each user can only claim subdomains listed in allowed_subdomains
[[users]]
username = "alice"
password = "change-me"
allowed_subdomains = ["staging", "preview"]

[[users]]
username = "bob"
password = "change-me-too"
allowed_subdomains = ["bob-sandbox"]

Run it:

./woho-server --config <CONFIG_FIEL>

2. Client usage

woho --address <SERVER_IP>:<PORT> --export-port <LOCAL_PORT> --username <USERNAME> --password <PASSWORD>

Your local app on 127.0.0.1:3000 is now reachable at http://dev.example.com (routed through the server's HTTP gateway on port 8080).

Client CLI reference

Wormhole Tunnel Client

Usage: woho [OPTIONS] --address <ADDRESS> --export-port <EXPORT_PORT> --username <USERNAME> --password <PASSWORD>

Options:
  -a, --address <ADDRESS>          Address of the woho-server (host:port)
  -e, --export-port <EXPORT_PORT>  Local port to expose to the internet
  -u, --username <USERNAME>        Username configured on the server
  -p, --password <PASSWORD>        Password configured on the server
  -s, --subdomain <SUBDOMAIN>      Requested subdomain (must be in your allowed list)
  -f, --force                      Force-close an existing session on the same
                                    subdomain and take it over
  -h, --help                       Print help

Note: --address currently expects an ip:port pair, not a hostname — resolve DNS yourself before passing it in.

Server configuration reference

Section Field Description
[server] listen_quic Address the QUIC control/data endpoint binds to
[server] listen_http Address the HTTP gateway binds to
[server] domain_suffix Suffix appended to a user's subdomain to form the public domain
[tls_config] cert_path / key_path TLS certificate and key used for the QUIC endpoint
[[static_routes]] subdomain / upstream Fixed subdomain → local address mapping, bypassing QUIC entirely
[[users]] username / password / allowed_subdomains Credentials and which subdomain(s) each user may request

Security notice

This project has not yet been hardened for production use. In particular, as of now:

  • The client does not verify the server's TLS certificate (certificate verification is disabled). Anyone able to intercept traffic between client and server can read or tamper with tunneled data.
  • The HTTP gateway has no request size limit or read timeout on the initial header parse, and does not validate that the Host header actually belongs to the configured domain_suffix.
  • There is no rate limiting on connections or requests.
  • Passwords are stored in plaintext in the server config.

Until these are addressed, run woho-server's HTTP gateway behind a reverse proxy (e.g. Caddy, Nginx, or Traefik) that terminates public TLS, enforces timeouts/body size limits, and ideally does its own authentication or IP allow-listing in front of it. Don't expose the raw HTTP gateway directly to untrusted traffic yet.

Known limitations / roadmap

  • No automatic reconnect on the client if the QUIC connection drops
  • No graceful shutdown (open tunnels are dropped abruptly on server restart)
  • --address requires a resolved IP, not a hostname
  • No metrics/observability for active tunnels or throughput
  • Passwords aren't hashed

License

Add a license (e.g. MIT or Apache-2.0) before publishing, if you haven't already.

About

Blazing-fast HTTP/TCP reverse tunneling tool built with Rust, powered by QUIC multiplexing and raw TCP routing.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages