Skip to content

Docs

Quickstart

The Wormhop agent runs next to your service and connects out to Wormhop's edge, so you don't need to open any inbound ports. This guide takes you from nothing to a public URL.

Install

On macOS or Linux:

$curl -fsSL https://github.com/jason-shen/wormhop-releases/releases/latest/download/install.sh | sh

Windows builds are on the releases page.

Authenticate

Create an account, then open the dashboard and create an authtoken. It's shown once, so copy it straight into the agent:

wormhop authtoken pw_xxxxxxxx --server tunnel.wormhop.dev

HTTP tunnels

wormhop http 3000                         # random subdomain
wormhop http 3000 --subdomain my-app      # reserved subdomain (Hobbyist and up)
wormhop http 8080 --hostname app.example.com --host-header rewrite --basic-auth me:secret

Every HTTP tunnel is also served over HTTPS with a trusted certificate. WebSockets work, and Wormhop adds X-Forwarded-For, X-Forwarded-Proto and X-Forwarded-Host. Use --host-header rewrite for dev servers such as Vite that reject unknown Host headers.

TCP and UDP

wormhop tcp 22 --remote-port 20022        # reserved TCP port
wormhop udp 27015                         # random UDP port
wormhop udp 30000-30099 --remote-port 30000   # a range of 100 UDP ports

Reserve ports in the dashboard under TCP & UDP ports. A range counts each port toward your plan's limit.

Config file

Define several tunnels once and start them together with wormhop start --all. Run wormhop config to see where the file lives.

Custom domains

  • Add the domain in the dashboard under Domains.
  • Create a CNAME to edge.wormhop.dev and the TXT record _wormhop-challenge.<your host> the dashboard shows you.
  • Click verify. Wormhop issues a Let's Encrypt certificate and renews it automatically.
  • Start a tunnel with --hostname home.example.com.

Restrictive networks

The agent normally connects on port 7000. On networks that block it, the agent connects through port 443 instead without printing anything. It tries both ports at once after a short head start for 7000, so a blocked port doesn't cost a timeout. Run with --log debug to see which port it used.

WebRTC and SFUs

Signalling goes over an HTTP tunnel, media over a UDP tunnel. Use the same port numbers locally and publicly, because SFUs advertise their own port in ICE candidates, and set the SFU's external IP to the Wormhop edge address.

SFUSingle portAdvertise server IP
PionSetICEUDPMuxSetNAT1To1IPs, SetLite(true)
LiveKitrtc.udp_portrtc.node_ip
mediasoupa WebRtcServerannouncedAddress
Janusrtp_port_rangenat_1_1_mapping

More in the WebRTC guide.

Performance

Measured on a 2-vCPU cloud VM with release builds. The server, agent, test client and an echo service all shared the same two cores over loopback, with TLS on the agent connection.

MeasurementServerAgent
Memory at idle11 MB6 MB
Memory with 1,000 open connections through one tunnel29 MB25 MB
CPU per GB relayed, including TLS2.2 s2.0 s
  • Throughput: 161 MB/s in each direction at once through one TCP tunnel (about 1.3 Gbit/s), limited by the two shared cores.
  • Latency added per HTTP request: 0.19 ms median.
  • WebRTC under loss: with 5% loss injected on the agent's link, 0.27% of RTP was lost after WebRTC's own recovery, and the median round trip stayed at 1.3 ms.