Documentation

Get up and running with SubTunnel in under a minute.

Quick Start

Install the CLI, point it at your server, and your local port is live on the internet.

Terminal
# 1. Install SubTunnel
$ curl -sSL https://www.subtunnel.dev/install.sh | sh

# 2. Expose a local port through your server
$ subtunnel local 3000 \
    --to your-server.example.com:7835 \
    --token YOUR_TOKEN \
    --subdomain myapp

Your local server on port 3000 is now accessible at https://myapp.your-domain.com

Installation

Install the SubTunnel CLI on macOS or Linux. A single binary, no dependencies.

macOS / Linux

$ curl -sSL https://www.subtunnel.dev/install.sh | sh

Supports macOS (Apple Silicon & Intel) and Linux (x86_64 & ARM64). The script detects your platform, downloads the latest release, and installs to /usr/local/bin.

Manual Download

Download the binary for your platform from the GitHub Releases page, extract it, and place it in your PATH.

Self-Hosting the Server

SubTunnel is fully self-hosted. You run the server on your own VPS (EC2, DigitalOcean, Hetzner, etc.) and connect clients to it. Here's how to set it up from scratch.

Prerequisites

  • A VPS with a public IP address (any Linux distro)
  • A domain name with DNS access (e.g. Cloudflare, Route 53)
  • Ports 7835 (control plane) and 8080 (HTTP traffic) open in your security group / firewall

1. DNS Setup

Point your domain and a wildcard subdomain to your server's IP address. This allows SubTunnel to route traffic to tunnels based on subdomain.

DNS Records
# Replace 203.0.113.10 with your server's public IP

A     tunnel.example.com      → 203.0.113.10
A     *.tunnel.example.com    → 203.0.113.10

2. Install SubTunnel on Your Server

SSH into your server
$ curl -sSL https://www.subtunnel.dev/install.sh | sh

3. Generate a Token

Create a shared secret that clients will use to authenticate with the server.

$ openssl rand -hex 16
# e.g. 1f881630ba330f5b4631070118b5d909

4. Set Up nginx (TLS Termination)

Use nginx as a reverse proxy to handle TLS termination and forward HTTP traffic to SubTunnel's HTTP listener. This gives you automatic HTTPS via Let's Encrypt.

nginx.conf
# Wildcard HTTPS — routes *.tunnel.example.com to SubTunnel
server {
    listen 443 ssl;
    server_name *.tunnel.example.com;

    ssl_certificate /etc/letsencrypt/live/tunnel.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tunnel.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

For wildcard certificates, use DNS-based validation with certbot: certbot certonly --dns-cloudflare -d tunnel.example.com -d *.tunnel.example.com

5. Start the Server

$ subtunnel server \
    --domain tunnel.example.com \
    --token YOUR_TOKEN \
    --port 7835 \
    --http-port 8080

6. Run as a systemd Service

For production, run SubTunnel as a systemd service so it starts on boot and auto-restarts.

/etc/systemd/system/subtunnel.service
[Unit]
Description=SubTunnel Server
After=network.target

[Service]
Type=simple
User=subtunnel
ExecStart=/usr/local/bin/subtunnel server \
    --domain tunnel.example.com \
    --token YOUR_TOKEN \
    --port 7835 \
    --http-port 8080
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
Enable and start
$ sudo systemctl enable subtunnel
$ sudo systemctl start subtunnel
$ sudo systemctl status subtunnel

7. Connect a Client

From your local machine, connect to your server:

$ subtunnel local 3000 \
    --to your-server.example.com:7835 \
    --token YOUR_TOKEN \
    --subdomain myapp

# ✓ Connected
# Forwarding: https://myapp.tunnel.example.com → localhost:3000

Architecture Overview

Internet → nginx (TLS :443) → SubTunnel HTTP (:8080) → route by Host header
                                                         ↕ yamux streams
Client (subtunnel local) ←— TLS + yamux (:7835) ——→ SubTunnel Server
        ↕                                              (control + data)
   localhost:PORT

CLI Reference

subtunnel server

Run the SubTunnel server on your VPS. This is the public-facing component that accepts client connections and routes traffic.

$ subtunnel server --domain tunnel.example.com --token SECRET

# All options:
$ subtunnel server \
    --domain tunnel.example.com \  # Required: base domain for subdomains
    --token SECRET \              # Auth token clients must provide
    --port 7835 \               # Control plane port (default: 7835)
    --http-port 8080 \           # HTTP listener port (default: 8080)
    --host 0.0.0.0 \             # Bind address (default: 0.0.0.0)
    --extra-domain other.com      # Accept additional domains

subtunnel local

Connect to a SubTunnel server and expose a local port to the internet.

$ subtunnel local 3000 --to server:7835 --token SECRET

# With a custom subdomain:
$ subtunnel local 3000 \
    --to server.example.com:7835 \
    --token SECRET \
    --subdomain myapp             # → myapp.tunnel.example.com

# Skip TLS verification (self-signed certs):
$ subtunnel local 3000 --to server:7835 --token SECRET --tls-verify false

# Use a custom CA certificate:
$ subtunnel local 3000 --to server:7835 --token SECRET --tls-ca /path/to/ca.pem

Configuration

SubTunnel can be configured via a subtunnel.yml file in your project root:

subtunnel.yml
server:
  url: https://tunnel.example.com

tunnels:
  web:
    proto: http
    addr: 3000
    domain: app.example.com

  api:
    proto: http
    addr: 8080
    domain: api.example.com

Then start all tunnels with: subtunnel start

Need help?

Join our community or check the full API reference.