Add TURN relay support and document coturn setup
Browser adapter reads turnURL + turnSecret from WASTE_CONFIG and adds a TURN ICEServer entry automatically. Uses time-limited credentials compatible with coturn's use-auth-secret mode. README: new section under Hosting with coturn install, turnserver.conf, firewall note (UDP 3478, no NPM needed), and config.js snippet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
44
README.md
44
README.md
@@ -86,6 +86,50 @@ If NPM doesn't support static file serving directly, run a small static server o
|
|||||||
- `/ws` → anchor process (WebSocket, keep-alive)
|
- `/ws` → anchor process (WebSocket, keep-alive)
|
||||||
- `/*` → static file server (SPA fallback: return `index.html` for unknown paths)
|
- `/*` → static file server (SPA fallback: return `index.html` for unknown paths)
|
||||||
|
|
||||||
|
### 4. TURN relay (optional, fixes mobile / CGNAT)
|
||||||
|
|
||||||
|
WebRTC hole-punching fails when both peers are behind symmetric NAT — common on mobile data and some ISPs. A TURN relay fixes this. It runs directly on the VPS, not through Nginx Proxy Manager.
|
||||||
|
|
||||||
|
**Firewall:** open UDP 3478 (and optionally TCP 3478) on the Hetzner firewall. No NPM config needed — coturn speaks its own protocol.
|
||||||
|
|
||||||
|
**Install coturn:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install coturn
|
||||||
|
```
|
||||||
|
|
||||||
|
**`/etc/turnserver.conf`:**
|
||||||
|
|
||||||
|
```
|
||||||
|
listening-port=3478
|
||||||
|
fingerprint
|
||||||
|
use-auth-secret
|
||||||
|
static-auth-secret=YOUR_RANDOM_SECRET
|
||||||
|
realm=your-domain.com
|
||||||
|
no-tcp-relay
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `YOUR_RANDOM_SECRET` with any random string (e.g. `openssl rand -hex 32`). Enable and start:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl enable coturn
|
||||||
|
systemctl start coturn
|
||||||
|
```
|
||||||
|
|
||||||
|
**Update `config.js`** to tell browsers about the TURN server:
|
||||||
|
|
||||||
|
```js
|
||||||
|
window.WASTE_CONFIG = {
|
||||||
|
signalURL: 'wss://your-domain.com/ws',
|
||||||
|
turnURL: 'turn:your-domain.com:3478',
|
||||||
|
turnSecret: 'YOUR_RANDOM_SECRET',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `use-auth-secret` mode generates short-lived TURN credentials from the shared secret — no user database required. The relay only sees opaque DTLS-encrypted blobs.
|
||||||
|
|
||||||
|
> The browser adapter reads `turnURL` and `turnSecret` from `WASTE_CONFIG` and adds the TURN server to the WebRTC `ICEServers` list automatically. If not configured, STUN-only is used (works for most desktop/home NAT situations).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## How it works: daemon vs browser mode
|
## How it works: daemon vs browser mode
|
||||||
|
|||||||
@@ -16,6 +16,17 @@ const EKEY_PREFIX = 'yaw/2.1 ekey'
|
|||||||
const FS_TIMEOUT = 2000
|
const FS_TIMEOUT = 2000
|
||||||
const STUN = 'stun:stun.l.google.com:19302'
|
const STUN = 'stun:stun.l.google.com:19302'
|
||||||
|
|
||||||
|
function iceServers(): RTCIceServer[] {
|
||||||
|
const cfg = (window as unknown as { WASTE_CONFIG?: { turnURL?: string; turnSecret?: string } }).WASTE_CONFIG
|
||||||
|
const servers: RTCIceServer[] = [{ urls: STUN }]
|
||||||
|
if (cfg?.turnURL && cfg?.turnSecret) {
|
||||||
|
// TURN with time-limited credentials derived from static-auth-secret
|
||||||
|
const user = Math.floor(Date.now() / 1000) + 3600 + ':waste'
|
||||||
|
servers.push({ urls: cfg.turnURL, username: user, credential: cfg.turnSecret })
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
const enc = (s: string) => new TextEncoder().encode(s)
|
const enc = (s: string) => new TextEncoder().encode(s)
|
||||||
|
|
||||||
function concat(...arrs: Uint8Array[]): Uint8Array {
|
function concat(...arrs: Uint8Array[]): Uint8Array {
|
||||||
@@ -263,7 +274,7 @@ class PeerConn {
|
|||||||
this.on = on
|
this.on = on
|
||||||
this.nick = nick
|
this.nick = nick
|
||||||
this.share = share
|
this.share = share
|
||||||
this.pc = new RTCPeerConnection({ iceServers: [{ urls: STUN }] })
|
this.pc = new RTCPeerConnection({ iceServers: iceServers() })
|
||||||
const kp = sodium.crypto_box_keypair()
|
const kp = sodium.crypto_box_keypair()
|
||||||
this._esk = kp.privateKey
|
this._esk = kp.privateKey
|
||||||
this._epk = kp.publicKey
|
this._epk = kp.publicKey
|
||||||
|
|||||||
Reference in New Issue
Block a user