Skip to content

serve_app

Expose a local development server to the internet via a reverse SSH tunnel through your VPS.

Usage

serve_app <local_port> <tunnel_name>

Tunnel → Port Table

Tunnel Name VPS Port Public URL
tunnel1 9201 https://tunnel1.mpltr.app
tunnel2 9202 https://tunnel2.mpltr.app
tunnel3 9203 https://tunnel3.mpltr.app

The VPS user is tunnels at 100.75.34.115.

Examples

# Expose a local Next.js dev server (port 3000) via tunnel1
serve_app 3000 tunnel1

# Expose a Vite dev server (port 5173) via tunnel2
serve_app 5173 tunnel2

Architecture

Request Flow

sequenceDiagram
    participant Browser
    participant DNS

    box Hetzner VPS (65.21.243.161)
        participant nginx
        participant Tailscale
    end

    participant dev as Dev Server (local)

    Browser->>DNS: tunnel1.mpltr.app
    DNS-->>Browser: 65.21.243.161

    Browser->>nginx: HTTPS :443
    Note over nginx: SSL termination

    nginx->>nginx: proxy to 127.0.0.1:9201

    Note over nginx,dev: ssh -R binds VPS :9201 → local :8000

    nginx->>Tailscale: Tailnet (100.75.34.115)
    Tailscale->>dev: localhost:8000
    dev-->>Tailscale: Response
    Tailscale-->>nginx: Response
    nginx-->>Browser: Response

How It Works

  1. Maps the tunnel name to a high-numbered VPS port (9201–9203).
  2. Opens a reverse SSH tunnel: ssh -N -R 127.0.0.1:<vps_port>:localhost:<local_port> tunnels@100.75.34.115.
  3. Traffic hitting the VPS port is forwarded back to your local port via Tailscale.

Infrastructure

  • Domain: mpltr.apptunnel{1,2,3}.mpltr.app A records point to the VPS
  • Server: VPS: Tunnel & Docs — Hetzner VPS running nginx + Certbot, Tailscale connected

Tailscale must be running locally to connect. The SSH tunnel uses the Tailscale IP (100.75.34.115), not the public IP.

Notes

  • The tunnel runs in the foreground — Ctrl+C to stop.
  • Only three tunnels are available. Use different tunnel names for concurrent services.