Open-source tunneling tool that exposes local services to the internet via secure HTTPS tunnels.
Built in Rust for maximum performance. Alternative to ngrok and Cloudflare Tunnel.
- Install
- Public Tunnels
- Local HTTPS
- Self-Hosting
- Why xpo?
- Features
- Commands
- Platform Support
- Contributing
- License
curl -fsSL https://xpo.sh/install | shOther methods
# Homebrew
brew install xpo-sh/tap/xpo
# npm
npm install -g @xposh/cli
# From source
cargo install xpoExpose any local port to the internet with a single command:
$ xpo login
✓ Logged in as you@email.com
$ xpo share 3000 -s myapp
xpo share
https://myapp.xpo.sh -> localhost:3000
42 requests 5ms avg 98% ok
● Connected you@email.com
TIME METHOD PATH STATUS
16:25:04 GET / 200 (3ms)
16:25:04 GET /_nuxt/ 304 (2ms)
16:25:05 POST /api/data 200 (1ms)
q:quit ↑↓:scroll f:filter x:clear ?:help
Real HTTPS on localhost with .test domains. No browser warnings, WebSocket/HMR works out of the box. Setup runs automatically on first use:
$ xpo dev 3000 -n myapp
xpo dev
https://myapp.test -> localhost:3000
12 requests 3ms avg 100% ok
● Connected
TIME METHOD PATH STATUS
16:25:04 GET / 200 (3ms)
16:25:04 GET /_nuxt/entry 304 (2ms)
16:25:05 GET /api/health 200 (1ms)
q:quit ↑↓:scroll f:filter x:clear ?:help
Basic self-hosting is available for the tunnel server. This is the edge component only: you bring your own domain, auth provider, DNS, and ops.
- Prepare a JWT public key PEM from your auth provider
- Point
*.your-domain.tldto your server - Export the required env vars
- Start the public profile
cd xpo
export PUBLIC_BASE_DOMAIN=tunnel.example.com
export PUBLIC_REGION=home
export PUBLIC_ACME_EMAIL=ops@example.com
export PUBLIC_CF_API_TOKEN=your_cloudflare_api_token
export PUBLIC_CF_ZONE_ID=your_cloudflare_zone_id
export JWT_PUBLIC_KEY_FILE=/absolute/path/to/jwt-public.pem
docker compose --profile public up -d xpo-server-publicRequired files:
JWT_PUBLIC_KEY_FILEmust point to a PEM public key used by your auth provider- Cloudflare DNS must be able to create
_acme-challengeTXT records for your zone
Important notes:
xpo.shcloud pricing does not apply to self-hosted deployments- Self-hosted runs under the MIT license and does not enforce Free/Pro limits
- You operate auth, TLS, uptime, abuse prevention, and support yourself
xpo.shhosted-only features such as managed billing, hosted dashboard, and managed multi-region do not automatically appear in self-hosted mode
| xpo | ngrok | Cloudflare Tunnel | |
|---|---|---|---|
| Open source | ✅ MIT (client + server) | ❌ Proprietary | |
| Self-hostable | ✅ | ❌ | ❌ |
| Local HTTPS | ✅ .test domains |
❌ | ❌ |
| Custom subdomains | ✅ | 💰 Paid | ✅ |
| Written in | Rust | Go | Go |
| Binary size | ~5 MB | ~30 MB | ~40 MB |
| WebSocket relay | ✅ | ✅ | ✅ |
- 🔒 HTTPS tunnels - Let's Encrypt wildcard TLS, zero config
- ⚡ WebSocket relay - HMR/hot-reload works through tunnel
- 🏠 Local HTTPS - trusted
.testdomains with auto-renewing certs - 🌍 CORS injection -
--corsflag adds permissive CORS headers, handles preflight - 🔒 Password protection -
--passwordflag adds HTTP Basic Auth to tunnels - ⏱️ Tunnel TTL -
--ttl 30mauto-expires tunnels after a duration - ⏳ Wait for upstream -
--waitpolls until your dev server is ready - 📋 List tunnels -
xpo listshows active tunnels and local dev domains - 🔄 Auto-reconnect - exponential backoff on connection loss
- 📦 Self-update -
xpo updateto get the latest version - 🖥️ Interactive TUI - Ratatui-powered dashboard with QR code, request log, filtering
- 📊 Request logging - colored terminal output with timing
- 🏷️ Custom subdomains -
xpo share 3000 -s myapp - 🔑 GitHub/Google auth - OAuth login, no email/password
- 🚀 Fast - Rust + tokio, sub-millisecond proxy overhead
- 💚 Open source - MIT licensed
xpo login # authenticate with GitHub or Google
xpo share <port> # public HTTPS tunnel
xpo share <port> -s <name> # custom subdomain
xpo share <port> --cors # inject CORS headers + handle preflight
xpo share <port> --password s3cr # password-protect tunnel (Basic Auth)
xpo share <port> --ttl 30m # auto-expire tunnel after 30 minutes
xpo share <port> --wait # wait for upstream port before connecting
xpo list # show active tunnels and dev domains
xpo list --json # machine-readable output
xpo dev <port> -n <name> # local HTTPS proxy (auto-setup on first use)
xpo dev setup # manual setup (CA, trust, port forwarding)
xpo dev stop # clean up /etc/hosts entries
xpo dev uninstall # remove CA, trust, and port forwarding
xpo doctor # diagnose setup issues
xpo update # self-update to latest version
xpo status # show session info
xpo logout # clear session| Platform | xpo dev |
xpo share |
|---|---|---|
| macOS (ARM + Intel) | ✅ Full | ✅ Full |
| Linux (x86_64 + ARM) | ✅ Full | ✅ Full |
| Windows | - | ✅ Full |
We welcome contributions! Here's how you can help:
