1
mirror of https://github.com/s4turns/BroFerence.git synced 2026-06-13 22:54:14 +00:00
interdome 44990d4c19 Merge pull request #23 from s4turns/testing
Fix screen-share audio feedback loop (echo cancellation)
2026-05-31 22:10:57 -05:00

BroFerence — WebRTC Video Conferencing

Live demo: https://broference.cam/

image image

A self-hosted, multi-participant WebRTC video conferencing app. No accounts, no third-party media servers — just a Python signaling server, dual TURN relay, and a browser client.


Features

  • Multi-participant video — Unlimited users per room (mesh topology, best for ≤10)
  • Real-time text chat — In-app messaging with optional IRC bridge
  • Password-protected rooms — PBKDF2-HMAC-SHA256 hashed, per-room
  • AI Noise Suppression — Adjustable noise gate with real-time mic level visualization
  • Microphone selector — Switch input device live, including NVIDIA Broadcast / RTX Voice
  • Low Bandwidth Mode — Caps video to 480p/15fps and audio to 32kbps
  • Video quality selector — 480p, 720p, or 1080p; persists across sessions
  • Moderator controls — Kick, mute, rename, promote/demote co-moderators
  • Moderator succession — Auto-transfers to next user by join order on mod disconnect
  • End-to-end encryption — Optional AES-GCM-256 for audio and video (moderator-toggled)
  • Speaking indicator — Glowing ring pulses with voice activity
  • Connection quality indicator — Signal bars showing RTT and packet loss
  • Per-user volume controls — Independent volume per participant
  • Per-participant hide video — Disables inbound track decoding to save CPU/GPU
  • DEFCON button — Kill all video feeds instantly
  • Screen share with audio mixer — Independent mic and desktop audio sliders
  • Hardware codec preference — H.264 → VP9 → AV1 → VP8
  • Gravatar avatars — Set your email in Options; shared peer-to-peer automatically
  • Nickname persistence — Display name saved and auto-filled on return
  • Spotlight mode — Click any video to fullscreen it
  • Theme selector — Matrix, Cyberpunk, Ocean, Sunset, Amber, Corporate
  • Mobile optimized — Tap-to-unmute, auto noise suppression on mobile
  • IRC bridge (on-demand) — Bridge rooms to IRC channels when needed
  • Multi-domain SSL — Auto-discovers Let's Encrypt certs across domains
  • Dual TURN relay — Two independent coturn servers, asymmetric ICE paths, no third-party TURN needed
  • Echo cancellation, noise suppression, auto gain control — Built-in audio enhancements

Quick Start

Local Development

Windows:

start-local-dev.bat

Linux/Mac:

chmod +x start-local-dev.sh && ./start-local-dev.sh

Opens at http://localhost:8080


Production Deployment

Prerequisites: Docker, Docker Compose, a domain with DNS pointed at your server, SSL certificates (Let's Encrypt recommended).

1. Clone the repo

git clone https://github.com/s4turns/BroFerence.git
cd BroFerence

2. Get SSL certificates

apt install certbot
certbot certonly --standalone -d yourdomain.com

3. Deploy

bash update-vps.sh

update-vps.sh handles everything in one shot:

  • Pulls latest code
  • Generates a new random TURN credential
  • Auto-detects your server's public IP
  • Updates TURN config and client JS
  • Rebuilds and restarts all Docker containers
  • Syncs fail2ban config if installed

4. (First time) Set up fail2ban

sudo bash setup-fail2ban.sh

5. Open firewall ports

Port Protocol Purpose
22 TCP SSH
443 TCP HTTPS
8080 TCP HTTP (redirects to HTTPS)
8765 TCP WebSocket signaling
3479 TCP+UDP TURN
4915265535 UDP TURN relay

Components

Signaling Server (server/)

Python + WebSockets. Handles room management, WebRTC offer/answer/ICE relay, password protection, IRC bridge, and SSL cert discovery.

TURN Servers (config/)

Two independent Coturn instances for asymmetric relay — covers same-NAT hairpin without a third-party provider. Credentials auto-rotate on every deploy.

Web Client (client/)

Vanilla JS + WebRTC API. No frameworks. Mesh peer connections, dynamic video grid, audio worklet noise gate, E2E encryption worker.


Usage

Joining a Room

  1. Open the app in your browser
  2. Enter your name (auto-filled from last visit)
  3. Enter a room name
  4. Optionally set a room password or IRC channel
  5. Click Continue → configure camera/mic → Join Room
https://yourdomain.com/?room=RoomName
https://yourdomain.com/?room=RoomName&name=YourName

Controls

Control Action
🎤 Mute/unmute mic
📹 Camera on/off
🖥️ Share screen (with optional audio)
💬 Toggle chat sidebar
Options panel
Click video Spotlight/fullscreen that participant
Hover video Volume slider for that participant

Options Panel

  • Change name mid-call
  • Gravatar email
  • AI Noise Suppression + threshold
  • Low Bandwidth Mode
  • Video quality (480p / 720p / 1080p)
  • Theme selector
  • Copy invite link
  • DEFCON (all video off/on)
  • E2E Encryption (moderator only)
  • Leave room

Connection Quality

Signal bars in the bottom-right of each video tile:

Bars Colour Meaning
4 Green Excellent (RTT < 100ms, loss < 1%)
3 Green Good
2 Yellow Fair
1 Red Poor

Hover the bars for exact RTT and packet loss numbers.


Configuration

TURN Server

TURN credentials are auto-rotated by update-vps.sh on every deploy. To manually set credentials, edit config/turnserver.production.conf:

user=webrtc:YOUR_STRONG_PASSWORD
realm=yourdomain.com
external-ip=YOUR_PUBLIC_IP

And update PRIMARY_TURN_CREDENTIAL in client/conference.js to match.

Second TURN Server

A second independent Coturn instance at a separate IP improves relay coverage. Configure its IP in the turn2Config block in client/conference.js:

const turn2Config = {
    urls: ['turn:YOUR_SECOND_TURN_IP:3479', 'turn:YOUR_SECOND_TURN_IP:3479?transport=tcp'],
    username: 'webrtc',
    credential: 'YOUR_SECOND_CREDENTIAL'
};

SSL Certificates

The signaling server auto-discovers certs in priority order:

  1. ./ssl/ — local/custom certs
  2. /etc/letsencrypt/live/ — Let's Encrypt (all domains scanned)
  3. /etc/ssl/ — system fallback

Supported filenames: fullchain.pem / cert.pem / certificate.pem and privkey.pem / key.pem / private.pem.

IRC Bridge

On-demand only — no IRC connection is made unless a user specifies a channel on room creation. To configure the IRC server, edit server/irc_bridge.py (default: no server configured).


Security

Layers

Layer What it does
Cloud firewall (Linode/etc.) Drops traffic before it reaches the server
iptables Host-level INPUT DROP policy, rate-limited SSH, DOCKER-USER WebSocket flood limiting
fail2ban Bans IPs after repeated SSH / nginx / TURN auth failures
PBKDF2 room passwords 260k iterations, random salt — not reversible
E2E encryption Optional AES-GCM-256 for audio/video streams
TURN credential rotation New random 32-char credential on every deploy

fail2ban Jails

Jail Watches Bans after
sshd /var/log/auth.log 5 failures / 10 min → 24h ban
nginx-botsearch nginx access log 10 hits / 1 min → 1h ban
nginx-req-limit nginx error log 10 hits / 1 min → 1h ban
coturn-auth TURN log 10 failures / 1 min → 1h ban

iptables (INPUT chain)

loopback         → ACCEPT
ESTABLISHED      → ACCEPT
SSH :22          → ACCEPT (rate-limited: 4 new/min)
HTTPS :443       → ACCEPT
HTTP  :8080      → ACCEPT
WS    :8765      → ACCEPT
TURN  :3479 TCP  → ACCEPT
TURN  :3479 UDP  → ACCEPT
Relay :49152-65535 UDP → ACCEPT
everything else  → DROP

DOCKER-USER: rate-limits new WebSocket connections to 20/min per IP.


Helper Scripts

Script Purpose
update-vps.sh Full deploy: pull, rotate TURN creds, rebuild containers, sync fail2ban
setup-fail2ban.sh Install and configure fail2ban (run as root, first time only)
setup-turn-ip.sh Manually set TURN external-ip in config
test-turn-server.sh Diagnose TURN server connectivity
start-local-dev.sh / .bat Start local dev server

All scripts are generic — no hardcoded hostnames or paths. They auto-detect from their environment or accept overrides via environment variables:

# setup-fail2ban.sh
REPO_DIR=/opt/BroFerence APP_USER=myuser sudo bash setup-fail2ban.sh

# setup-turn-ip.sh
./setup-turn-ip.sh yourdomain.com

# test-turn-server.sh
HOSTNAME=yourdomain.com TURN_PORT=3479 bash test-turn-server.sh

Project Structure

BroFerence/
├── client/
│   ├── app.html               # Main conference UI
│   ├── conference.js          # WebRTC logic, ICE, media, UI
│   ├── e2ee-worker.js         # AES-GCM-256 E2E encryption worker
│   ├── noise-processor.js     # Audio worklet noise gate
│   ├── styles.css             # Retro terminal themes
│   └── admin.html             # Admin panel
├── server/
│   ├── signaling_server_v2.py # Production WSS server
│   ├── signaling_server_local.py # Local WS server (no SSL)
│   └── irc_bridge.py          # IRC bridge integration
├── config/
│   ├── turnserver.production.conf  # Production TURN config (auto-updated by deploy)
│   └── turnserver.conf             # Dev/local TURN config
├── fail2ban/
│   ├── jail.local             # fail2ban jail definitions
│   └── filter.d/
│       ├── coturn-auth.conf   # TURN auth failure filter
│       └── nginx-req-limit.conf # Nginx rate limit filter
├── ssl/                       # SSL certificates (gitignored)
├── logs/                      # Container log mounts for fail2ban (gitignored)
├── docker-compose.yml
├── Dockerfile.web
├── update-vps.sh              # Deploy script
├── setup-fail2ban.sh          # fail2ban setup (run as root)
├── setup-turn-ip.sh           # TURN IP config helper
└── test-turn-server.sh        # TURN diagnostic

Troubleshooting

WebSocket won't connect

docker compose logs signaling
docker compose ps

Video slow to connect or not connecting

  • Run ./test-turn-server.sh to verify TURN is reachable
  • Check external-ip in TURN config matches your server's actual public IP
  • Verify relay ports 4915265535 UDP are open in your firewall

TURN relay shows wrong IP

# update-vps.sh auto-fixes this on deploy, or manually:
./setup-turn-ip.sh yourdomain.com
grep external-ip config/turnserver.production.conf

fail2ban not starting

# Ensure log dirs exist (setup-fail2ban.sh creates them, or manually):
sudo mkdir -p /path/to/BroFerence/logs/nginx /path/to/BroFerence/logs/coturn
sudo systemctl restart fail2ban
sudo fail2ban-client status

Browser cache issues

Ctrl+Shift+N  # Incognito/private window
F12 → Network → Disable cache

Full container rebuild

docker compose down -v
docker compose build --no-cache --pull
docker compose up -d

Browser Compatibility

Browser Support
Chrome / Edge 90+
Firefox 88+
Safari 14.1+
Opera 76+
Internet Explorer

Requires: WebRTC, WebSocket, getUserMedia, getDisplayMedia, AudioWorklet.


Development

# Python linting
cd server && pip install flake8
flake8 *.py --max-line-length=120

# JS linting
cd client && npx eslint *.js

Dependencies (Python):

  • websockets>=12.0
  • cryptography>=41.0.0
pip install -r server/requirements.txt

Recent Updates

v1.8 (2026-05)

  • New domain — Migrated to broference.cam
  • TURN realm — Updated to broference.cam across all configs
  • fail2ban — SSH, nginx, and TURN jails with log volume mounts from containers
  • iptables — INPUT DROP policy, rate-limited SSH, DOCKER-USER WebSocket flood protection
  • Generic scripts — All setup scripts now auto-detect hostname/paths, no hardcoded values

v1.7 (2026-04-26)

  • Gravatar support — Hashed client-side, broadcast peer-to-peer
  • Nickname persistence — Saved to localStorage, auto-filled on return
  • Video quality selector — 480p / 720p / 1080p, persists across sessions
  • Options menu consolidation — Invite, DEFCON, bug report moved into options panel
  • Room name in tab title
  • Dual coturn relay — Replaced Metered.ca dependency with second self-hosted coturn

v1.6 (2026-04-01)

  • Per-participant hide video — Disables inbound track decoding to save CPU/GPU
  • DEFCON button — Kill all video feeds at once
  • Screen share audio mixer — Independent mic/desktop audio sliders
  • Hardware codec preference — H.264 → VP9 → AV1 → VP8
  • Corporate theme
  • AI Noise Suppression off by default
  • PBKDF2 password hashing — PBKDF2-HMAC-SHA256, 260k iterations
  • XSS hardening — All user strings sanitized before DOM insertion

v1.5 (2026-03-25)

  • Low Bandwidth Mode — 480p/15fps, capped bitrates
  • Moderator succession — Auto-transfers on mod disconnect
  • iOS/Safari fix — Zero relay candidate fallback to P2P
  • WebSocket reconnect — Preserves already-connected peers

v1.4 (2026-03-25)

  • ICE restart on disconnect — Triggers after 6s, fixes silent dead connections
  • WebSocket auto-reconnect — Exponential backoff (2s → 30s)
  • Cache-busting — Git commit hash stamped on asset URLs

v1.3 (2026-02-18)

  • Microphone device selector — Switch live, supports NVIDIA Broadcast / RTX Voice
  • Fixed scratchy audio from Math.exp in audio worklet hot path
  • Fixed outgoing audio distortion and mobile glitchy audio

v1.2 (2026-02)

  • AI Noise Suppression — Adjustable noise gate with mic level viz
  • Per-user volume controls
  • Theme selector — 5 themes
  • Screen share with audio
  • E2E encryption — AES-GCM-256 (moderator-controlled)

v1.1 (2026-02)

  • Multi-domain SSL certificate auto-discovery
  • On-demand IRC bridge
  • Dynamic hostname detection in update script

v1.0 (2026-01)

  • Initial release — multi-participant video, TURN server, IRC bridge, Matrix UI

GitHub · Issues

Description
A complete WebRTC video chat application with Python signaling server and local TURN server.
Readme 7.6 MiB
Languages
JavaScript 90.2%
Python 3.6%
HTML 2.7%
CSS 2.5%
Shell 0.8%
Other 0.2%