mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2026-04-08 14:56:49 +00:00
145 lines
6.4 KiB
Markdown
145 lines
6.4 KiB
Markdown
# Tunnel Setup (Self-Hosting Behind NAT)
|
|
|
|
Expose your self-hosted Reflector + LiveKit stack to the internet without port forwarding, static IPs, or cloud VMs using tunneling services.
|
|
|
|
## Requirements
|
|
|
|
You need **two tunnels**:
|
|
|
|
| Tunnel | Protocol | What it carries | Local port | Examples |
|
|
|--------|----------|----------------|------------|----------|
|
|
| **TCP tunnel** | TCP | Web app, API, LiveKit signaling (WebSocket) | 443 (Caddy) | playit.gg, ngrok, Cloudflare Tunnel, bore, frp |
|
|
| **UDP tunnel** | UDP | WebRTC audio/video media | Assigned by tunnel service | playit.gg, frp |
|
|
|
|
> **Important:** Most tunneling services only support TCP. WebRTC media requires UDP. Make sure your chosen service supports UDP tunnels. As of writing, [playit.gg](https://playit.gg) is one of the few that supports both TCP and UDP (premium $3/mo).
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Internet participants
|
|
│
|
|
├── TCP tunnel (HTTPS)
|
|
│ └── tunnel service → your machine port 443 (Caddy)
|
|
│ ├── /v1/* → server:1250 (API)
|
|
│ ├── /lk-ws/* → livekit-server:7880 (signaling)
|
|
│ └── /* → web:3000 (frontend)
|
|
│
|
|
└── UDP tunnel
|
|
└── tunnel service → your machine port N (LiveKit ICE)
|
|
```
|
|
|
|
## Setup
|
|
|
|
### Step 1: Create tunnels with your chosen service
|
|
|
|
Create two tunnels and note the public addresses:
|
|
|
|
- **TCP tunnel**: Points to your local port `443`
|
|
- You'll get an address like `your-tunnel.example.com:PORT`
|
|
- **UDP tunnel**: Points to a local port (e.g., `14139`)
|
|
- You'll get an address like `udp-host.example.com:PORT`
|
|
- **The local port must match the public port** (or LiveKit ICE candidates won't match). Set the local port to the same number as the public port assigned by the tunnel service.
|
|
|
|
### Step 2: Run the setup script
|
|
|
|
```bash
|
|
./scripts/setup-selfhosted.sh <mode> --livekit --garage \
|
|
--tunnels <TCP_ADDRESS>,<UDP_ADDRESS>
|
|
```
|
|
|
|
Example:
|
|
```bash
|
|
./scripts/setup-selfhosted.sh --cpu --livekit --garage \
|
|
--tunnels my-tunnel.example.com:9055,udp-host.example.com:14139
|
|
```
|
|
|
|
Or use separate flags:
|
|
```bash
|
|
./scripts/setup-selfhosted.sh --cpu --livekit --garage \
|
|
--tunnel-tcp my-tunnel.example.com:9055 \
|
|
--tunnel-udp udp-host.example.com:14139
|
|
```
|
|
|
|
The script automatically:
|
|
- Sets all URLs (API, frontend, LiveKit signaling) to the TCP tunnel address
|
|
- Configures LiveKit with the UDP tunnel port and resolved IP for ICE candidates
|
|
- Enables Caddy with self-signed TLS (catch-all on port 443)
|
|
- Saves tunnel config for re-runs
|
|
|
|
### Step 3: Start the tunnel agent
|
|
|
|
Run your tunneling service's agent/client on the same machine. It must be running whenever you want external access.
|
|
|
|
### Step 4: Access
|
|
|
|
Share `https://<TCP_TUNNEL_ADDRESS>` with participants. They'll need to accept the self-signed certificate warning in their browser.
|
|
|
|
## Flag Reference
|
|
|
|
| Flag | Description |
|
|
|------|-------------|
|
|
| `--tunnels TCP,UDP` | Both tunnel addresses comma-separated (e.g., `host:9055,host:14139`) |
|
|
| `--tunnel-tcp ADDR` | TCP tunnel address only (e.g., `host.example.com:9055`) |
|
|
| `--tunnel-udp ADDR` | UDP tunnel address only (e.g., `host.example.com:14139`) |
|
|
|
|
Tunnel flags:
|
|
- Imply `--caddy` (HTTPS required for browser mic/camera access)
|
|
- Are mutually exclusive with `--ip` and `--domain`
|
|
- Are saved to config memory (re-run without flags replays saved config)
|
|
|
|
## UDP Port Matching
|
|
|
|
LiveKit advertises ICE candidates with a specific IP and port. The browser connects to that exact address. If the tunnel's public port differs from the local port, ICE will fail.
|
|
|
|
**Correct setup:** Set the tunnel's local port to match its public port.
|
|
|
|
```
|
|
Tunnel assigns public port 14139
|
|
→ Set local port to 14139
|
|
→ LiveKit listens on 14139 (udp_port in livekit.yaml)
|
|
→ Docker maps 14139:14139/udp
|
|
→ ICE candidates advertise tunnel_ip:14139
|
|
→ Browser connects to tunnel_ip:14139 → tunnel → local:14139 → LiveKit
|
|
```
|
|
|
|
If your tunneling service doesn't let you choose the local port, you'll need to update `livekit.yaml` manually with the assigned ports.
|
|
|
|
## TLS Certificate Warning
|
|
|
|
With tunnel services on non-standard ports (e.g., `:9055`), Let's Encrypt can't auto-provision certificates (it requires ports 80/443). Caddy uses `tls internal` which generates a self-signed certificate. Participants will see a browser warning they must accept.
|
|
|
|
**To avoid the warning:**
|
|
- Use a tunnel service that provides port 443 for TCP
|
|
- Or use a real domain with `--domain` on a server with a public IP
|
|
|
|
## Compatible Tunnel Services
|
|
|
|
| Service | TCP | UDP | Free tier | Notes |
|
|
|---------|-----|-----|-----------|-------|
|
|
| [playit.gg](https://playit.gg) | Yes (premium) | Yes (premium) | Limited | $3/mo premium. Supports both TCP + UDP. |
|
|
| [ngrok](https://ngrok.com) | Yes | No | Limited | TCP only — needs a separate UDP tunnel for media |
|
|
| [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) | Yes | No | Yes | TCP only — needs a separate UDP tunnel for media |
|
|
| [bore](https://github.com/ekzhang/bore) | Yes | No | Self-hosted | TCP only |
|
|
| [frp](https://github.com/fatedier/frp) | Yes | Yes | Self-hosted | Requires your own VPS to run the frp server |
|
|
| [Tailscale Funnel](https://tailscale.com/kb/1223/funnel) | Yes | No | Free (3 nodes) | TCP only, requires Tailscale account |
|
|
|
|
For a full self-contained setup without a VPS, playit.gg (TCP + UDP) is currently the simplest option.
|
|
|
|
## Limitations
|
|
|
|
- **Latency**: Adds a hop through the tunnel service's relay servers
|
|
- **Bandwidth**: Tunnel services may have bandwidth limits on free/cheap tiers
|
|
- **Reliability**: Depends on the tunnel service's uptime
|
|
- **Certificate warning**: Unavoidable with non-standard ports (see above)
|
|
- **Single UDP port**: Tunnel mode uses a single UDP port instead of a range, which limits concurrent WebRTC connections (~50 participants max)
|
|
- **Not production-grade**: Suitable for demos, small teams, development, and privacy-first setups. For production, use a server with a public IP.
|
|
|
|
## Comparison
|
|
|
|
| Approach | Cost | Setup | Data location | Port forwarding needed |
|
|
|----------|------|-------|---------------|----------------------|
|
|
| **Tunnel (this guide)** | $0-3/mo | Low | Your machine | No |
|
|
| **Cloud VM** | $5-20/mo | Low | Cloud provider | No |
|
|
| **Port forwarding** | $0 | Medium | Your machine | Yes (router config) |
|
|
| **VPN mesh (Tailscale)** | $0 | Low | Your machine | No (VPN peers only) |
|