A self-hosted ngrok alternative built in Rust. Expose your local services to the internet through secure tunnels.
Quick Start
Installation
# Clone and build git clone https://github.com/copyleftdev/zgrok.git cd zgrok cargo build --release # Binaries are in target/release/ ls target/release/zgrok target/release/zgrok-edge
Expose a Local Service
# Start a tunnel to your local server on port 8080 ./target/release/zgrok http 8080 # With a custom subdomain ./target/release/zgrok http 8080 --subdomain myapp # With authentication ./target/release/zgrok http 8080 --authtoken zg_your_token_here
Run Your Own Edge Server
# Generate TLS certificates (or use Let's Encrypt) openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes # Start the edge server ./target/release/zgrok-edge \ --cert cert.pem \ --key key.pem \ --domain yourdomain.com \ --https-port 443 \ --http-port 80
Architecture
┌─────────────┐ HTTPS ┌─────────────┐ Multiplexed ┌─────────────┐
│ Browser │ ──────────────▶│ Edge │◀───────────────── │ Agent │
│ │ subdomain. │ Server │ Tunnel │ (CLI) │
└─────────────┘ domain.com └─────────────┘ └──────┬──────┘
│ │
│ │ HTTP
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Control │ │ Your │
│ Plane │ │ Service │
└─────────────┘ └─────────────┘
| Component | Crate | Description |
|---|---|---|
| Agent | zgrok-agent |
CLI client that runs on your machine |
| Edge | zgrok-edge |
Public server that terminates TLS and routes traffic |
| Control | zgrok-control |
Authentication, sessions, subdomain allocation |
| Protocol | zgrok-protocol |
Binary framing, stream multiplexing, keepalive |
| Common | zgrok-common |
Shared utilities, observability, validation |
Agent CLI Reference
zgrok - Expose local services via secure tunnels
USAGE:
zgrok [OPTIONS] <COMMAND>
COMMANDS:
http Start an HTTP tunnel
tcp Start a TCP tunnel
config Manage configuration
status Show tunnel status
OPTIONS:
-c, --config <PATH> Path to config file
-v, --verbose Increase verbosity (-v, -vv, -vvv)
--no-color Disable colored output
HTTP Tunnel Options
zgrok http [OPTIONS] <PORT>
ARGUMENTS:
<PORT> Local port to expose
OPTIONS:
--host <HOST> Local host to forward to [default: localhost]
-s, --subdomain <SUBDOMAIN> Request specific subdomain
--authtoken <TOKEN> API key for authentication
--region <REGION> Edge region to connect to
--inspect Enable request inspection UI
Configuration File
Create ~/.config/zgrok/config.toml:
authtoken = "zg_your_token_here" region = "us-east" [defaults] inspect = true [tunnels.webapp] proto = "http" addr = "8080" subdomain = "myapp" [tunnels.api] proto = "http" addr = "3000" subdomain = "api"
Edge Server Reference
zgrok-edge - Edge/gateway server for zgrok tunneling service
OPTIONS:
--https-port <PORT> HTTPS listen port [default: 443]
--http-port <PORT> HTTP redirect port, 0 to disable [default: 80]
--listen <ADDR> Listen address [default: 0.0.0.0]
--cert <PATH> TLS certificate (PEM)
--key <PATH> TLS private key (PEM)
--domain <DOMAIN> Base domain for subdomains [default: zgrok.io]
--control-url <URL> Control plane URL
-v, --verbose Enable verbose logging
Environment Variables
| Variable | Description |
|---|---|
ZGROK_AUTHTOKEN |
Default authentication token |
ZGROK_CERT_PATH |
TLS certificate path |
ZGROK_KEY_PATH |
TLS private key path |
ZGROK_CONTROL_URL |
Control plane endpoint |
Deployment
Docker
FROM rust:1.75 as builder WORKDIR /app COPY . . RUN cargo build --release FROM debian:bookworm-slim RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /app/target/release/zgrok-edge /usr/local/bin/ EXPOSE 443 80 ENTRYPOINT ["zgrok-edge"]
Systemd Service
# /etc/systemd/system/zgrok-edge.service [Unit] Description=zgrok Edge Server After=network.target [Service] Type=simple User=zgrok ExecStart=/usr/local/bin/zgrok-edge \ --cert /etc/zgrok/cert.pem \ --key /etc/zgrok/key.pem \ --domain example.com Restart=always RestartSec=5 [Install] WantedBy=multi-user.target
Wildcard DNS
Configure your DNS with a wildcard A record:
*.tunnel.example.com A <your-edge-server-ip>
Then run the edge server with --domain tunnel.example.com.
Features
- Stream Multiplexing: Multiple logical streams over a single TCP connection
- TLS Termination: Secure connections with automatic HTTPS
- Subdomain Routing: Each tunnel gets a unique subdomain
- Rate Limiting: Protection against abuse (per-IP, per-account, per-subdomain)
- Connection Limits: Resource protection with configurable limits
- Health Checks: Kubernetes-ready liveness and readiness probes
- Prometheus Metrics: Built-in observability
- Distributed Tracing: OpenTelemetry support
- Graceful Shutdown: Clean connection draining
Development
# Run all tests cargo test # Run with verbose output cargo test -- --nocapture # Lint cargo clippy -- -D warnings # Format cargo fmt # Build release cargo build --release
Project Structure
crates/
├── zgrok-protocol/ # Wire protocol, frame codec, multiplexer
├── zgrok-agent/ # CLI client with TUI
├── zgrok-edge/ # Public-facing gateway server
├── zgrok-control/ # Auth, sessions, subdomain allocation
├── zgrok-common/ # Shared types, observability, validation
└── zgrok-integration-tests/ # Cross-crate integration tests
License
MIT
Contributing
See CONTRIBUTING.md for guidelines.