diff --git a/deploy/coturn/README.md b/deploy/coturn/README.md new file mode 100644 index 0000000..5b6be56 --- /dev/null +++ b/deploy/coturn/README.md @@ -0,0 +1,44 @@ +# Self-hosted TURN (coturn) for BizGaze Connect + +Why: customers behind symmetric NAT / corporate firewalls / VPNs can't form a direct +WebRTC path, so screen share blanks out and disconnects. A TURN relay fixes it. We host +our own coturn on a VM we already own — flat cost, no per-GB billing. + +## 1. VM prerequisites +- A VM with a **public IP** (your data-center VM is fine). +- A DNS A record, e.g. `turn.yourdomain.com` -> that public IP. +- A TLS cert for that name (Let's Encrypt): `certbot certonly --standalone -d turn.yourdomain.com` + +## 2. Open firewall ports (on the VM and any edge firewall) +- `3478/udp` and `3478/tcp` (STUN/TURN) +- `5349/tcp` (TURN over TLS) — and `443/tcp` if you enable alt-tls +- `49152-65535/udp` (relay range) + +## 3. Configure +Edit `turnserver.conf`: +- `external-ip=` your VM's public IP +- `static-auth-secret=` a long random string (e.g. `openssl rand -hex 32`) +- `realm=` your domain +- `cert=` / `pkey=` paths to your Let's Encrypt cert + +## 4. Run +``` +docker compose up -d # uses docker-compose.yml here +# or native: apt install coturn; copy this file to /etc/turnserver.conf; enable in /etc/default/coturn; systemctl enable --now coturn +``` + +## 5. Point the app at it (production env) +``` +TURN_URLS=turn:turn.yourdomain.com:3478,turn:turn.yourdomain.com:3478?transport=tcp,turns:turn.yourdomain.com:5349?transport=tcp +TURN_SECRET= +TURN_TTL=86400 +``` +The app's `/api/ice` mints short-lived credentials from `TURN_SECRET` automatically — no +permanent password is exposed, and outsiders can't reuse your relay. Restart the app. + +## 6. Verify +- `GET https:///api/ice` should return a `turn:`/`turns:` entry with a username + credential. +- Test page: https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ + Add your `turns:turn.yourdomain.com:5349?transport=tcp` with the username/credential from + `/api/ice`; you should see a candidate of type **relay**. If you do, restrictive networks + are covered. diff --git a/deploy/coturn/docker-compose.yml b/deploy/coturn/docker-compose.yml new file mode 100644 index 0000000..8d506f1 --- /dev/null +++ b/deploy/coturn/docker-compose.yml @@ -0,0 +1,12 @@ +# Run coturn on your VM: docker compose up -d +# host networking is required so the UDP relay port range works without per-port mapping. +services: + coturn: + image: coturn/coturn:latest + container_name: coturn + restart: unless-stopped + network_mode: host + volumes: + - ./turnserver.conf:/etc/coturn/turnserver.conf:ro + - /etc/letsencrypt:/etc/letsencrypt:ro # TLS cert for turns: + command: ["-c", "/etc/coturn/turnserver.conf"] diff --git a/deploy/coturn/turnserver.conf b/deploy/coturn/turnserver.conf new file mode 100644 index 0000000..c606eb6 --- /dev/null +++ b/deploy/coturn/turnserver.conf @@ -0,0 +1,45 @@ +# coturn config for BizGaze Connect self-hosted TURN. +# Put this on your VM (public IP) and run via Docker (see docker-compose.yml) or +# native coturn (apt install coturn). Replace every CHANGE_ME / placeholder. + +# --- listening --- +listening-port=3478 +tls-listening-port=5349 +# If this VM has a spare 443, also exposing TURNS on 443 gives the best traversal +# through strict corporate firewalls (uncomment + ensure nothing else uses 443): +# alt-tls-listening-port=443 + +# Public address clients reach. If the VM has a 1:1 NAT, use external-ip=PUBLIC/PRIVATE. +external-ip=CHANGE_ME_PUBLIC_IP + +# Relay port range (open these UDP ports in the firewall too). +min-port=49152 +max-port=65535 + +# --- auth: time-limited shared-secret credentials (matches the app's TURN_SECRET) --- +use-auth-secret +static-auth-secret=CHANGE_ME_LONG_RANDOM_SECRET +realm=connect.yourdomain.com + +# --- TLS (needed for turns: on 5349/443). Use a real cert for turn.yourdomain.com --- +cert=/etc/letsencrypt/live/turn.yourdomain.com/fullchain.pem +pkey=/etc/letsencrypt/live/turn.yourdomain.com/privkey.pem + +# --- hardening --- +fingerprint +no-cli +no-multicast-peers +no-tcp-relay +# Block relaying to private/internal ranges (prevents your relay being used to reach +# your own LAN / cloud metadata — important SSRF protection): +denied-peer-ip=0.0.0.0-0.255.255.255 +denied-peer-ip=10.0.0.0-10.255.255.255 +denied-peer-ip=100.64.0.0-100.127.255.255 +denied-peer-ip=169.254.0.0-169.254.255.255 +denied-peer-ip=172.16.0.0-172.31.255.255 +denied-peer-ip=192.168.0.0-192.168.255.255 +denied-peer-ip=::1 +denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +# Optional: cap per-session bandwidth (bytes/sec) to protect the VM, e.g. 700000 = ~5.6 Mbps +# bps-capacity=0 +# total-quota=100 diff --git a/server/public/connect.html b/server/public/connect.html index dea61c7..4471fb3 100644 --- a/server/public/connect.html +++ b/server/public/connect.html @@ -68,7 +68,7 @@