Tear a rift through the wire. Expose localhost to the world.
Open-source, zero-dependency tunnel server and client written in Go. Expose any local service to the internet through a secure tunnel — like ngrok, but fully self-hosted.
- Features
- Installation
- Quick Start
- Server Reference
- Client Reference
- Dashboard
- Configuration
- Access Control
- Traffic Inspector
- Docker
- API Reference
- Architecture
- Benchmarks
- Development
- License
| Category | Features |
|---|---|
| Tunneling | HTTP tunnels, TCP tunnels, WebSocket passthrough, stream multiplexing, flow control |
| Security | Let's Encrypt ACME, self-signed TLS, Basic Auth, IP whitelist (CIDR), PIN protection, HMAC cookies, CSP nonce |
| Monitoring | Web dashboard (dark/light theme), traffic inspector, request replay, cURL export, JSON highlighting |
| Operations | Health check (/healthz), X-Request-ID tracing, graceful shutdown, auto-reconnect, rate limiting |
| Config | YAML and JSON config files, CLI flags, environment variables, user-defined tokens |
| Platform | Zero dependencies, single binary, Linux/macOS/Windows/FreeBSD, amd64/arm64 |
Download the latest release for your platform from GitHub Releases.
Linux (amd64)
curl -Lo wirerift-server https://github.com/WireRift/WireRift/releases/latest/download/wirerift-server-linux-amd64
curl -Lo wirerift https://github.com/WireRift/WireRift/releases/latest/download/wirerift-linux-amd64
chmod +x wirerift-server wirerift
sudo mv wirerift-server wirerift /usr/local/bin/Linux (arm64 / Raspberry Pi)
curl -Lo wirerift-server https://github.com/WireRift/WireRift/releases/latest/download/wirerift-server-linux-arm64
curl -Lo wirerift https://github.com/WireRift/WireRift/releases/latest/download/wirerift-linux-arm64
chmod +x wirerift-server wirerift
sudo mv wirerift-server wirerift /usr/local/bin/macOS (Apple Silicon / M1+)
curl -Lo wirerift-server https://github.com/WireRift/WireRift/releases/latest/download/wirerift-server-darwin-arm64
curl -Lo wirerift https://github.com/WireRift/WireRift/releases/latest/download/wirerift-darwin-arm64
chmod +x wirerift-server wirerift
sudo mv wirerift-server wirerift /usr/local/bin/macOS (Intel)
curl -Lo wirerift-server https://github.com/WireRift/WireRift/releases/latest/download/wirerift-server-darwin-amd64
curl -Lo wirerift https://github.com/WireRift/WireRift/releases/latest/download/wirerift-darwin-amd64
chmod +x wirerift-server wirerift
sudo mv wirerift-server wirerift /usr/local/bin/Windows (amd64)
Download from Releases:
wirerift-server-windows-amd64.exewirerift-windows-amd64.exe
Or via PowerShell:
Invoke-WebRequest -Uri "https://github.com/WireRift/WireRift/releases/latest/download/wirerift-server-windows-amd64.exe" -OutFile "wirerift-server.exe"
Invoke-WebRequest -Uri "https://github.com/WireRift/WireRift/releases/latest/download/wirerift-windows-amd64.exe" -OutFile "wirerift.exe"Windows (arm64)
Download from Releases:
wirerift-server-windows-arm64.exewirerift-windows-arm64.exe
Requires Go 1.23+:
git clone https://github.com/WireRift/WireRift.git
cd WireRift
go build -o wirerift-server ./cmd/wirerift-server
go build -o wirerift ./cmd/wireriftOr with Make:
make build # builds both server and client to bin/
make test # run all tests
make test-race # run tests with race detector
make fuzz # run fuzz tests
make bench # run benchmarks
make docker # build Docker image
make release # cross-compile all platforms to dist/# With a fixed token (recommended)
wirerift-server --token my-secret-token
# Or let the server generate a random token (shown on startup)
wirerift-serverThe server prints a connection banner:
╔══════════════════════════════════════════════╗
║ WireRift Server ║
╠══════════════════════════════════════════════╣
Control: :4443
HTTP: :80
Dashboard: http://localhost:4040
Domain: wirerift.com
╠══════════════════════════════════════════════╣
Token (-token flag):
my-secret-token
╠══════════════════════════════════════════════╣
Quick start:
wirerift http 8080 -server localhost:4443 -token my-secret-token
╚══════════════════════════════════════════════╝
# Expose local port 8080 via HTTP tunnel
wirerift http 8080 --token my-secret-token
# With custom subdomain
wirerift http 8080 myapp --token my-secret-token
# TCP tunnel (e.g., PostgreSQL)
wirerift tcp 5432 --token my-secret-token
# Serve static files
wirerift serve ./dist --token my-secret-tokenVisit http://localhost:4040 and enter your token to see:
- Active tunnels and sessions
- Live traffic inspector
- Request replay and cURL export
wirerift-server [options]
Options:
--token string Auth token (default: auto-generated random)
--domain string Base domain for tunnels (default: wirerift.com)
--control string Control plane address (default: :4443)
--http string HTTP edge address (default: :80)
--https string HTTPS edge address (default: :443)
--dashboard-port int Dashboard port (default: 4040)
--tcp-ports string TCP tunnel port range (default: 20000-29999)
--auto-cert Generate self-signed certificates
--cert-dir string Certificate directory (default: certs)
--acme-email string Email for Let's Encrypt (enables ACME)
--acme-staging Use Let's Encrypt staging server
--v Verbose logging
--json JSON log format
--version Show version
Environment Variables:
WIRERIFT_TOKEN Auth token (flag takes precedence)
WIRERIFT_DOMAIN Base domain
WIRERIFT_CONTROL_ADDR Control plane address
WIRERIFT_HTTP_ADDR HTTP edge address
# Development (localhost, self-signed TLS)
wirerift-server --token dev123 --auto-cert
# Production (Let's Encrypt)
wirerift-server --domain mytunnel.com --acme-email admin@mytunnel.com --token prod-secret
# Custom ports
wirerift-server --control :8443 --http :8080 --dashboard-port 9090 --token mytoken
# Via environment
export WIRERIFT_TOKEN=my-secret
export WIRERIFT_DOMAIN=tunnel.example.com
wirerift-server --acme-email admin@example.comwirerift <command> [options]
Commands:
http <port> [subdomain] Create an HTTP tunnel
tcp <port> Create a TCP tunnel
serve <directory> Serve static files via HTTP tunnel
start [config-file] Start tunnels from config file
list List active tunnels
config Show/edit configuration
version Show version info
Common Options (all commands):
--server string Server address (default: localhost:4443)
--token string Auth token (or set WIRERIFT_TOKEN env var)
--v Verbose output
HTTP/Serve Options:
--subdomain string Requested subdomain
--auth string Basic auth "user:password"
--pin string PIN protection
--whitelist string IP whitelist "ip1,ip2,cidr"
--header string Response headers "Key:Val,Key:Val"
--inspect Enable traffic inspector
Note: Both
--flagand-flagsyntax work. Flags can appear before or after positional arguments.
# Simple HTTP tunnel
wirerift http 3000 --token mytoken
# HTTP tunnel with all features
wirerift http 8080 myapp \
--token mytoken \
--auth "admin:pass" \
--pin 1234 \
--whitelist "10.0.0.0/8,192.168.1.0/24" \
--header "X-Frame-Options:DENY,X-Robots-Tag:noindex" \
--inspect
# TCP tunnel (database, game server, SSH, etc.)
wirerift tcp 5432 --token mytoken
wirerift tcp 25565 --token mytoken # Minecraft
wirerift tcp 22 --token mytoken # SSH
# Serve a directory
wirerift serve ./build --subdomain mysite --token mytoken
# Start from config file
wirerift start wirerift.yaml
wirerift start wirerift.jsonThe built-in dashboard at http://localhost:4040 provides:
- Dark/Light theme — toggle with button or persisted preference
- Tabbed navigation — Tunnels / Sessions / Inspector with live count badges
- Keyboard shortcuts —
Rrefresh,Ttunnels,Ssessions,Iinspector - Tunnel management — copy URL to clipboard, status indicators
- Traffic Inspector — real-time request/response log with:
- Method badges (GET=green, POST=blue, PUT=amber, DELETE=red)
- Status code coloring (2xx=green, 4xx=red, 5xx=red)
- Expandable request/response headers
- JSON syntax highlighting
- cURL command export
- Request replay
- Animated counters — bytes and uptime update smoothly
- Search/filter — filter across all tables
- Toast notifications — action feedback
# wirerift.yaml
server: localhost:4443
token: my-secret-token
tunnels:
- type: http
local_port: 8080
subdomain: myapp
- type: http
local_port: 9090
subdomain: admin
auth: "admin:secret"
pin: "mysecret"
whitelist: "10.0.0.0/8"
inspect: true
headers: "X-Robots-Tag:noindex"
- type: tcp
local_port: 5432{
"server": "localhost:4443",
"token": "my-secret-token",
"tunnels": [
{
"type": "http",
"local_port": 8080,
"subdomain": "myapp"
},
{
"type": "http",
"local_port": 9090,
"subdomain": "admin",
"auth": "admin:secret",
"pin": "mysecret",
"whitelist": "10.0.0.0/8",
"inspect": true,
"headers": "X-Robots-Tag:noindex"
},
{
"type": "tcp",
"local_port": 5432
}
]
}wirerift start wirerift.yaml # YAML
wirerift start wirerift.json # JSON (auto-fallback if .yaml not found)
wirerift config init # generate sample wirerift.yamlToken is resolved in order: --token flag > WIRERIFT_TOKEN env > auto-generated.
# Flag (highest priority)
wirerift-server --token my-secret
wirerift http 8080 --token my-secret
# Environment variable
export WIRERIFT_TOKEN=my-secret
wirerift-server # reads from env
wirerift http 8080 # reads from env
# Auto-generated (shown on server startup banner)
wirerift-server # generates random token, prints to stderrwirerift http 8080 --auth "user:password"Returns 401 Unauthorized with WWW-Authenticate: Basic header. Uses constant-time comparison.
wirerift http 8080 --whitelist "203.0.113.50,10.0.0.0/8,192.168.0.0/16"Supports IPv4, IPv6, CIDR notation. HTTP returns 403 Forbidden, TCP silently drops.
wirerift http 8080 --pin mysecretThree ways to provide PIN:
| Method | Example |
|---|---|
| Browser form | Dark-themed PIN page, sets HttpOnly HMAC cookie (24h) |
| HTTP header | X-WireRift-PIN: mysecret |
| Query parameter | https://myapp.tunnel.com/?pin=mysecret (redirects to clean URL) |
Enable inspection on any tunnel:
wirerift http 8080 --inspect --token mytokenDashboard shows live traffic at http://localhost:4040 (Inspector tab):
- Method, path, status, duration, client IP
- Expandable request/response headers
- JSON body with syntax highlighting
- Replay — resend any captured request
- cURL export — copy request as curl command
# List captured requests
curl -H "Authorization: Bearer TOKEN" http://localhost:4040/api/requests?limit=50
# Filter by tunnel
curl -H "Authorization: Bearer TOKEN" http://localhost:4040/api/requests?tunnel_id=tun_abc
# Replay a request
curl -X POST -H "Authorization: Bearer TOKEN" http://localhost:4040/api/requests/req_xyz/replaydocker build -t wirerift-server .
docker run -d \
-p 4443:4443 \
-p 80:80 \
-p 443:443 \
-p 4040:4040 \
-e WIRERIFT_TOKEN=my-secret \
-v wirerift-certs:/data/certs \
wirerift-server \
-domain mytunnel.com -auto-certdocker compose up -dThe included docker-compose.yml provides:
- Server with control, HTTP, HTTPS, dashboard ports
- TCP tunnel port range (20000-20099)
- Certificate volume persistence
- Health check via
/healthz - Non-root container
All endpoints require Authorization: Bearer TOKEN header.
| Endpoint | Method | Description |
|---|---|---|
/healthz |
GET | Health check (no auth required) |
/api/stats |
GET | Server statistics |
/api/tunnels |
GET | List active tunnels |
/api/sessions |
GET | List connected sessions |
/api/requests |
GET | List captured requests |
/api/requests/{id}/replay |
POST | Replay a captured request |
/api/domains |
GET/POST | List/add custom domains |
/api/domains/{domain} |
GET/DELETE | Get/remove domain |
/api/domains/{domain}/dns |
GET | DNS records for verification |
/api/domains/{domain}/verify |
POST | Verify domain ownership |
Every proxied request includes:
X-Request-ID— unique trace ID (preserved if sent by client)
+--------+--------+----------+-----------+
| Version| Type | StreamID | Length |
| 1 byte | 1 byte | 3 bytes | 4 bytes |
+--------+--------+----------+-----------+
| Payload (variable) |
+----------------------------------------+
Magic: 0x57 0x52 0x46 0x01 ("WRF\x01")
Header: 9 bytes | Max payload: 16 MB | Max streams: 16M
Client Server
|------- Magic + AUTH_REQ -------->|
|<------------- AUTH_RES ----------|
|------- TUNNEL_REQ -------------->| http://myapp.tunnel.com
|<------------- TUNNEL_RES -------|
| |
| [ Browser hits myapp.tunnel.com ]
| |
|<------ STREAM_OPEN(1) ----------| New HTTP request
|<------ STREAM_DATA(1) ----------|
|------- STREAM_DATA(1) --------->| Response from local service
|------- STREAM_CLOSE(1) -------->|
| |
|<------ STREAM_OPEN(2) ----------| Concurrent request!
|------- HEARTBEAT --------------->| Keep-alive
|<------------- HEARTBEAT_ACK ----|
wirerift/
├── cmd/
│ ├── wirerift/ # Client CLI
│ └── wirerift-server/ # Server CLI
├── internal/
│ ├── auth/ # Token authentication
│ ├── client/ # Client implementation
│ ├── config/ # Configuration & domains
│ ├── dashboard/ # Web dashboard & traffic inspector
│ ├── mux/ # Stream multiplexing & flow control
│ ├── proto/ # Wire protocol (frame encoding)
│ ├── ratelimit/ # Token bucket & sliding window
│ ├── server/
│ │ ├── server.go # Core server, session & tunnel management
│ │ ├── http_edge.go # HTTP request routing & proxying
│ │ ├── pin.go # PIN protection
│ │ ├── inspect.go # Traffic inspection & replay
│ │ ├── http_proxy.go # Request serialization
│ │ ├── tcp_proxy.go # TCP stream helpers
│ │ └── webhook.go # Webhook fan-out relay
│ ├── tls/ # ACME (Let's Encrypt) & certificate management
│ └── utils/ # Subdomain validation
├── test/
│ ├── advanced/ # Security, stress, reconnect, soak tests (34 tests)
│ ├── benchmark/ # Throughput & latency benchmarks
│ └── integration/ # End-to-end integration tests
├── Dockerfile # Multi-stage build (alpine, non-root, healthcheck)
├── docker-compose.yml # Production-ready compose file
├── Makefile # Build, test, lint, fuzz, release targets
└── .golangci.yml # Linter config (gosec, bodyclose, noctx, etc.)
Tested on AMD Ryzen 9 9950X3D, Windows 11, Go 1.23 (localhost):
| Metric | Value |
|---|---|
| Healthz latency | 553 µs avg |
| HTTP latency overhead | ~0.5 ms (small), ~0 ms (1KB+) |
| Download throughput | 99.6 MB/s |
| Single-thread RPS | 10,063 req/s |
| 10 concurrent | 10,335 req/s |
| 50 concurrent | 6,303 req/s |
| 100 concurrent | 4,143 req/s |
| Tunnel creation | 3,163 tunnels/sec (0.3 ms each) |
go run ./test/benchmark/ # Throughput & latency
go run ./test/advanced/ # Security, stress, reconnect, soak (34 tests)
go test -bench=. ./internal/ # Micro-benchmarks- Go 1.23+
- Git
go test ./... # All unit tests (15 packages)
go test -race ./... # With race detector
go test -cover ./... # With coverage
go run ./test/advanced/ # Advanced E2E suite (34 tests)
go run ./test/benchmark/ # Benchmark suite| Package | Coverage |
|---|---|
| internal/auth | 100% |
| internal/client | 100% |
| internal/config | 100% |
| internal/mux | 100% |
| internal/proto | 100% |
| internal/ratelimit | 100% |
| internal/utils | 100% |
| internal/server | 99.7% |
| internal/dashboard | 99.3% |
| internal/tls | 97.4% |
| cmd/wirerift | 99.6% |
| cmd/wirerift-server | 97.9% |
go vet ./...
golangci-lint run ./... # uses .golangci.yml config| Protection | Implementation |
|---|---|
| Authentication | Token-based, constant-time comparison |
| TLS | Let's Encrypt ACME (HTTP-01) or self-signed |
| Basic Auth | Per-tunnel, constant-time comparison |
| IP Whitelist | IPv4/IPv6/CIDR per-tunnel |
| PIN Protection | HMAC cookies (per-instance secret), HttpOnly, Secure, SameSite=Strict |
| Rate Limiting | Per-IP HTTP requests, per-session tunnel creation |
| CSP | Nonce-based Content-Security-Policy on dashboard |
| Headers | X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy |
| CSRF | Cookie auth restricted to GET requests on dashboard |
| Request Tracing | X-Request-ID auto-generated or preserved |
| Graceful Shutdown | HTTP server drain on SIGTERM/SIGINT |
| Panic Recovery | All production goroutines protected |
Make sure the server is running and the port matches:
wirerift http 8080 --server localhost:4443 --token YOUR_TOKENToken must match between server and client:
wirerift-server --token abc123 # server
wirerift http 8080 --token abc123 # client — same tokenChange the server ports:
wirerift-server --control :8443 --http :8080 --dashboard-port 9090Client automatically reconnects with exponential backoff (1s → 30s max) and re-creates all tunnels. No action needed.
MIT License — see LICENSE