Skip to content

xpo-sh/xpo

Repository files navigation

xpo.sh - Expose local services via secure tunnels

Website Crates.io npm CI License GitHub Stars

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

curl -fsSL https://xpo.sh/install | sh
Other methods
# Homebrew
brew install xpo-sh/tap/xpo

# npm
npm install -g @xposh/cli

# From source
cargo install xpo

Public tunnels

Expose 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

Local HTTPS

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

Self-Hosting

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.

  1. Prepare a JWT public key PEM from your auth provider
  2. Point *.your-domain.tld to your server
  3. Export the required env vars
  4. 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-public

Required files:

  • JWT_PUBLIC_KEY_FILE must point to a PEM public key used by your auth provider
  • Cloudflare DNS must be able to create _acme-challenge TXT records for your zone

Important notes:

  • xpo.sh cloud 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.sh hosted-only features such as managed billing, hosted dashboard, and managed multi-region do not automatically appear in self-hosted mode

Why xpo?

xpo ngrok Cloudflare Tunnel
Open source ✅ MIT (client + server) ❌ Proprietary ⚠️ Client only (Apache 2.0)
Self-hostable
Local HTTPS .test domains
Custom subdomains 💰 Paid
Written in Rust Go Go
Binary size ~5 MB ~30 MB ~40 MB
WebSocket relay

Features

  • 🔒 HTTPS tunnels - Let's Encrypt wildcard TLS, zero config
  • WebSocket relay - HMR/hot-reload works through tunnel
  • 🏠 Local HTTPS - trusted .test domains with auto-renewing certs
  • 🌍 CORS injection - --cors flag adds permissive CORS headers, handles preflight
  • 🔒 Password protection - --password flag adds HTTP Basic Auth to tunnels
  • ⏱️ Tunnel TTL - --ttl 30m auto-expires tunnels after a duration
  • Wait for upstream - --wait polls until your dev server is ready
  • 📋 List tunnels - xpo list shows active tunnels and local dev domains
  • 🔄 Auto-reconnect - exponential backoff on connection loss
  • 📦 Self-update - xpo update to 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

Commands

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 support

Platform xpo dev xpo share
macOS (ARM + Intel) ✅ Full ✅ Full
Linux (x86_64 + ARM) ✅ Full ✅ Full
Windows - ✅ Full

Contributing

We welcome contributions! Here's how you can help:

License

MIT

Website · X/Twitter · GitHub

Packages

 
 
 

Contributors

Languages