The open-source, single-binary alternative to ngrok. Expose your local
localhostserver to the internet with zero config, zero signup, and zero hassle.
Expose is a modern Go-based tunneling tool that lets you share your local development environment with the world. Perfect for testing webhooks, mobile debugging, or showing off your work on localtunnel or Cloudflare networks.
| Feature | π Expose | ngrok | Cloudflare Tunnel | LocalTunnel (Node) |
|---|---|---|---|---|
| No Signup Required | β | β | β | β |
| Single Binary | β | β | β | β (requires Node.js) |
| Open Source | β | β | β | β |
| Language | Go | Go | Go | JS |
| Free Custom Domains | π§ (Planned) | π² Paid | β | β |
- π Multiple Providers: Switch between LocalTunnel and Cloudflare Tunnel instantly.
- β‘ Zero Friction: No accounts, no auth tokens, just run and go.
- π¦ Lightweight: A single <10MB binary with no external dependencies.
- π§ Developer Friendly: Written in pure Go, easy to contribute to or self-host.
# Install
go install github.com/kernelshard/expose/cmd/expose@latest
# Initialize config
expose init
# Start tunnel (defaults to port 3000)
expose tunnelexpose tunnel -P cloudflare -p 8080Download the latest binary for your OS (Windows, macOS, Linux) from the Releases Page. Unzip it and add it to your PATH.
go install github.com/kernelshard/expose/cmd/expose@latestgit clone https://github.com/kernelshard/expose.git
cd expose
go build -o expose ./cmd/expose
./expose --version$ expose init
β Config created: .expose.ymlCreates .expose.yml in current directory:
project: expose
port: 3000# Use config port
$ expose tunnel
β Tunnel (LocalTunnel) started for localhost:3000
β Public URL: https://quick-mammals-sing.loca.lt
β Forwarding to http://localhost:3000
β Provider: LocalTunnel
β Press Ctrl+C to stop
# Override port
$ expose tunnel --port 8080# List all config values
$ expose config list
project: expose
port: 3000
# Get specific value
$ expose config get port
3000
$ expose config get project
expose$ expose --version
expose version v0.1.2 (commit: d30c483, built: 2025-11-10)
$ expose init
β Config created: .expose.yml (project: expose, port: 3000)
$ python3 -m http.server 3000 &
Serving HTTP on 0.0.0.0 port 3000...
$ expose tunnel
π Tunnel[LocalTunnel] started for localhost:3000
β Public URL: https://ripe-garlics-add.loca.lt
β Forwarding to: http://localhost:3000
β Provider: LocalTunnel
Press Ctrl+C to stop
$ curl https://ripe-garlics-add.loca.lt
<!DOCTYPE HTML>... # Works!Tested on: Go 1.23, macOS 14, Ubuntu 22.04
expose/
βββ cmd/expose/ # CLI entry point
βββ internal/
β βββ cli/ # Cobra commands (thin layer)
β βββ config/ # YAML config management
β βββ provider/ # Tunnel provider interface
β βββ tunnel/ # Service layer (business logic)
β βββ version/ # Version metadata
βββ .expose.yml # User config (add to .gitignore per project)
Design principles:
- Interface-driven β
Providerinterface supports multiple tunnel backends - Clean separation β CLI β Service β Provider (no circular deps)
- Testable β Real file tests, injectable service layer
- One tunnel per process β Each
expose tunnelcommand runs independently (can run multiple on different ports) - No persistence β Public URLs change on restart
- CLI-only β No web UI or dashboard yet
See GitHub Issues for roadmap.
- Go 1.23+
- Git
git clone https://github.com/kernelshard/expose.git
cd expose
go mod download# Run all tests with race detector
go test ./... -v -race -cover
# Check coverage for specific packages
go test ./internal/config -cover
go test ./internal/tunnel -cover
go test ./internal/provider -covergo build -o expose ./cmd/expose
./expose --version# Without installing
go run cmd/expose/main.go tunnel
# Test with live server
python3 -m http.server 3000 # Terminal 1
./expose tunnel # Terminal 2Contributions welcome! See CONTRIBUTING.md for:
- Development workflow
- Branch strategy
- Testing requirements
- Code style guidelines
MIT License - see LICENSE for details.
Made with β€οΈ by @kernelshard
