The Problem
Developers need a quick way to expose a local service to the public internet for demos, webhook testing, or remote debugging. Existing solutions (e.g., ngrok) require sign‑up, proprietary binaries, or per‑tunnel configuration, which adds friction to short‑lived workflows.
What This Does
Wormhole delivers a single‑command, zero‑config tunnel built on Go and Cloudflare Workers. The core CLI lives in cmd/wormhole/main.go and invokes the Go client (internal/client/client.go) to negotiate a tunnel, start a local HTTP inspector (internal/inspect/server.go), and optionally run a TUI (runTUI) or headless logger (runHeadless).
The Cloudflare edge component (edge/src/*.ts) implements the worker that terminates TLS, forwards traffic, and persists tunnel metadata in SQLite migrations (edge/migrations/*.sql). The pkg/config/config.go supplies a tiny configuration struct used by both the CLI and the worker.
How It Is Wired
Execution begins at func main() in cmd/wormhole/main.go (line 27). The command parser routes to httpCmd, which calls runHeadless (or runTUI when a TTY is present). Both functions create a Client via internal/client.New (line 89) – this is the widest‑blast‑radius function, called from five places and reaching 20 distinct functions.
The Client:
- Opens a WebSocket transport (
internal/transport/ws.go → NewWSTransport → Connect). - Starts a local inspector server (
internal/inspect.NewServer→Start→Addr,Close). - Registers request callbacks (
OnRequest,OnStatus) that funnel every inbound request into aRecorder(internal/inspect/recorder.go → NewRecorder → Record).
Record is called 15 times across the codebase and stores entries in an in‑memory ring buffer; the inspector UI reads them via Entries. The HAR exporter (internal/inspect/har.go → BuildHAR) pulls from the same recorder, providing standardized logs.
The edge worker (edge/src/index.ts) imports tunnel.ts; these two files form a measured import cycle (high soundness risk). The worker reads tunnel metadata from the SQLite DB (via migrations) and forwards HTTP/WebSocket traffic back to the Go client over the established WebSocket.
Key hub functions:
| Function | Defined in | Callers | Calls |
|---|---|---|---|
Close | internal/inspect/server.go | 23 places | – |
NewRecorder | internal/inspect/recorder.go | 19 places | Record, makeEntry |
NewServer | internal/inspect/server.go | 16 places | Addr, Close |
Run (client) | internal/client/client.go | 15 places | transport, recorder, UI |
The call graph shows 205 internal edges; the most frequently invoked paths are Close → …, NewRecorder → Record, and NewServer → Addr. No external file effects (e.g., file‑system writes) are evident beyond the SQLite migrations used by the edge worker.
How To Use It
# Clone the upstream repository
git clone https://github.com/moses-y/wormhole
cd wormhole
# Build the Go binary (Makefile target)
make build # produces ./wormhole
# Run a tunnel (exposes local port 3000)
./wormhole http 3000
# Optional: custom subdomain
./wormhole http 3000 --subdomain myapp
# Disable the inspector
./wormhole http 3000 --no-inspect
The CLI requires no external configuration files; the only runtime dependency is network access to *.wormhole.bar (Cloudflare‑managed DNS). The edge worker is deployed automatically by the project’s release process (not part of the local build).
Real‑World Use
A CI pipeline that validates incoming webhooks can start a temporary tunnel before running integration tests:
./wormhole http 8080 --headless &
TUNNEL_URL=$(./wormhole status | grep URL | awk '{print $2}')
curl -X POST "$TUNNEL_URL/webhook" -d '{"event":"test"}'
The inspector (http://localhost:4040) shows the request in real time and allows replay if the test needs to be rerun.
Code Health & Issues
- High – Missing CI – No
.github/workflowsor other CI config; 25 source files are never built/tested automatically. - Medium – No Dependabot –
go.modandedge/package.jsonlack an automated dependency‑update bot. - High – Import cycle –
edge/src/index.ts↔edge/src/tunnel.tscreate a circular import, increasing maintenance risk. - High – Duplicated install scripts – Nearly identical 6‑line blocks appear in
deployments/install.sh,docs/install.sh,install.sh, andinternal/client/client.go. - Medium – Deep nesting –
cmd/wormhole/main.goreaches an indentation depth of 7, making the control flow hard to follow.
All findings are derived from deterministic static analysis; no additional issues were inferred.
The Bottom Line
Wormhole provides a functional, Go‑centric alternative to commercial tunneling services with a minimal CLI and a Cloudflare‑based edge worker. The core architecture is clear and testable, but the repository suffers from maintainability concerns (import cycle, duplicated scripts) and lacks CI automation. Teams comfortable with Go and willing to add a CI pipeline can adopt it quickly for short‑term exposure or webhook development.