Messaging, file sharing, and real-time meetings built on WebRTC, Signal Protocol, and zero-trust principles.
PeerWave is a self-hosted communication platform designed around a zero-trust model.
All sensitive data is encrypted on the client before transmission and is never accessible to the server.
PeerWave uses the following core technologies:
- Signal Protocol for end-to-end encrypted messaging and key exchange
- WebRTC for peer-to-peer audio, video, and data transport
- WebAuthn (Passkeys) for passwordless authentication
- Ephemeral session keys for media encryption during calls and meetings
The server is responsible only for:
- user and channel metadata
- encrypted message routing
- WebRTC signaling
At no point does the server have access to plaintext messages, files, media streams, or encryption keys.
New to PeerWave? Choose your deployment:
- Local Testing: Use Docker Compose (Simple) - No SSL, runs on localhost
- Production: Use Docker Compose + Traefik - Auto SSL with Let's Encrypt
- Custom Build: Use Manual Build - For developers
Files you'll need:
docker-compose.ymlordocker-compose.traefik.yml- Container orchestration.env- Your configuration (secrets, domain, etc.)livekit-config.yaml- Video server settingsnginx-livekit.conf- Proxy config (Traefik deployment only)
Choose the deployment method that fits your needs:
| Method | Use Case | Complexity | Source |
|---|---|---|---|
| Docker Compose (Simple) | Local dev, small deployments | ⭐ Easy | Docker Hub |
| Docker Compose + Traefik | Production with SSL | ⭐⭐ Medium | Docker Hub |
| Manual Build | Custom modifications | ⭐⭐⭐ Advanced | Source Code |
Perfect for local development or simple deployments without reverse proxy. Uses pre-built images from Docker Hub.
# 1. Download configuration files (recommended)
# Download only what you need:
# - docker-compose.yml
# - docker-compose.traefik.yml (if using Traefik)
# - server/.env.example or .env.traefik.example
#
# You can use:
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/docker-compose.yml
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/docker-compose.traefik.yml
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/server/.env.example
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/.env.traefik.example
#
# Or download from GitHub web UI.
#
# For developers: clone the repo if you want to build or modify the source.
# 2. Copy environment template
cp server/.env.example server/.env
# 3. Edit configuration - CHANGE THE SECRETS!
nano server/.env
# Required: SESSION_SECRET, LIVEKIT_API_KEY, LIVEKIT_API_SECRET
# 4. Start all services (images pulled from Docker Hub)
docker-compose up -d
# 5. View logs
docker-compose logs -f peerwave-server✅ Images: Automatically pulled from Docker Hub (no build needed!)
✅ Certificates:
- Option A: Provide your own - place
turn-cert.pemandturn-key.pemin./livekit-certs/and restart - Option B: Auto-generated self-signed (default, no manual setup needed!)
Access PeerWave: http://localhost:3000
Best for production deployments with automatic HTTPS via Let's Encrypt. Uses pre-built images from Docker Hub.
- Traefik running with Let's Encrypt configured
- Domain pointing to your server
- Ports 80, 443 open for Traefik
- Proxy network created:
docker network create proxy
# 1. Download configuration files (recommended)
# Download only what you need:
# - docker-compose.traefik.yml
# - .env.traefik.example
# - livekit-config.yaml (if customizing TURN domain)
# - nginx-livekit.conf.example (rename to nginx-livekit.conf)
#
# You can use:
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/docker-compose.traefik.yml
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/.env.traefik.example
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/livekit-config.yaml
# wget https://raw.githubusercontent.com/simonzander/PeerWave/main/nginx-livekit.conf.example
#
# Or download from GitHub web UI.
#
# For developers: clone the repo if you want to build or modify the source.
# 2. Copy Traefik environment template
cp .env.traefik.example .env
# 3. Copy nginx proxy configuration
cp nginx-livekit.conf.example nginx-livekit.conf
# 3. Copy nginx proxy configuration
cp nginx-livekit.conf.example nginx-livekit.conf
# 4. Edit configuration
nano .envRequired variables:
DOMAIN=app.yourdomain.com
HTTPS=true
LIVEKIT_TURN_DOMAIN=app.yourdomain.com
TRAEFIK_ACME_PATH=/etc/traefik/acme.json # Your Traefik's acme.json path
LIVEKIT_CONFIG_PATH=/data/compose/25/livekit-config.yaml # Absolute path
NGINX_LIVEKIT_CONFIG_PATH=/data/compose/25/nginx-livekit.conf # Absolute path
SESSION_SECRET=$(openssl rand -base64 32)
LIVEKIT_API_KEY=$(openssl rand -base64 32)
LIVEKIT_API_SECRET=$(openssl rand -base64 32)# 5. Update livekit-config.yaml with your domain and API keys
nano livekit-config.yaml
# Set: turn.domain: app.yourdomain.com
# Set: keys section with your LIVEKIT_API_KEY: LIVEKIT_API_SECRET
# 6. Verify nginx-livekit.conf (usually no changes needed)
# Should have: proxy_pass http://172.17.0.1:7880;
# 7. Start services (images pulled from Docker Hub, certs extracted automatically!)
docker-compose -f docker-compose.traefik.yml up -d
# 8. View logs
docker-compose -f docker-compose.traefik.yml logs -f✅ Images: Automatically pulled from Docker Hub (no build needed!)
✅ Certificates: Auto-extracted from Traefik's acme.json (no manual setup needed!)
Access PeerWave: https://app.yourdomain.com
For developers who want to customize PeerWave or contribute to development.
# 1. Clone repository
git clone https://github.com/simonzander/PeerWave.git
cd PeerWave
# 2. Build Flutter web client
cd client
flutter build web --release
cp -r build/web ../server/web
# 3. Build Docker image
cd ../server
docker build -t peerwave-custom:latest .
# 4. Update docker-compose.yml to use your custom image
# Change: image: simonzander/peerwave:latest
# To: image: peerwave-custom:latest
# 5. Configure and start
cp .env.example .env
nano .env # Set your secrets
cd ..
docker-compose up -d📦 Build Script: Use the provided build script for easier building:
# Linux/macOS
chmod +x build-docker.sh
./build-docker.sh v1.0.0
# Windows PowerShell
.\build-docker.ps1 v1.0.0
# Build and push to Docker Hub
./build-docker.sh v1.0.0 --pushAccess PeerWave: http://localhost:3000
| Variable | Description | Required | Example |
|---|---|---|---|
DOMAIN |
Your domain | ✅ Traefik | app.yourdomain.com |
HTTPS |
Enable HTTPS/secure cookies | ✅ Traefik | true |
SESSION_SECRET |
Session encryption key | ✅ Yes | $(openssl rand -base64 32) |
LIVEKIT_API_KEY |
LiveKit API key | ✅ Yes | $(openssl rand -base64 32) |
LIVEKIT_API_SECRET |
LiveKit API secret | ✅ Yes | $(openssl rand -base64 32) |
LIVEKIT_TURN_DOMAIN |
Your domain for TURN | ✅ Prod | app.yourdomain.com |
TRAEFIK_ACME_PATH |
Path to Traefik's acme.json | ✅ Traefik | /etc/traefik/acme.json |
LIVEKIT_CONFIG_PATH |
Path to livekit-config.yaml | ✅ Traefik | /data/compose/25/livekit-config.yaml |
NGINX_LIVEKIT_CONFIG_PATH |
Path to nginx-livekit.conf | ✅ Traefik | /data/compose/25/nginx-livekit.conf |
| Variable | Description | Default | Example |
|---|---|---|---|
PORT |
Server port | 3000 |
4000 |
NODE_ENV |
Environment | production |
development |
APP_URL |
Base application URL | http://localhost:3000 |
https://app.yourdomain.com |
HTTPS |
Enable secure cookies | false |
true |
EMAIL_HOST |
SMTP server (optional) | - | smtp.gmail.com |
EMAIL_PORT |
SMTP port | 587 |
587 |
EMAIL_SECURE |
Use SSL/TLS | false |
true |
EMAIL_USER |
SMTP username | - | your-email@gmail.com |
EMAIL_PASS |
SMTP password | - | your-app-password |
EMAIL_FROM |
From address | no-reply@domain |
"PeerWave" <noreply@yourdomain.com> |
ADMIN_EMAILS |
Comma-separated admin emails | - | admin@example.com,admin2@example.com |
CLEANUP_INACTIVE_USER_DAYS |
Days until user marked inactive | 30 |
60 |
CLEANUP_SYSTEM_MESSAGES_DAYS |
System message retention | 1 |
3 |
CLEANUP_REGULAR_MESSAGES_DAYS |
Regular message retention | 7 |
14 |
CLEANUP_GROUP_MESSAGES_DAYS |
Group message retention | 7 |
30 |
CLEANUP_CRON_SCHEDULE |
Cleanup cron schedule | 0 2 * * * |
0 3 * * * |
CORS_ORIGINS |
Allowed origins | Auto | https://app.yourdomain.com |
server/.env (Simple deployment):
# Required
SESSION_SECRET=your-long-random-string-here
LIVEKIT_API_KEY=your-livekit-key
LIVEKIT_API_SECRET=your-livekit-secret
# Optional - Email (for meeting invitations)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_SECURE=true
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
EMAIL_FROM="PeerWave" <noreply@yourdomain.com>
# Optional - Admin users
ADMIN_EMAILS=admin@example.com,admin2@example.com.env (Traefik deployment):
# Required
DOMAIN=app.yourdomain.com
LIVEKIT_TURN_DOMAIN=app.yourdomain.com
TRAEFIK_ACME_PATH=/etc/traefik/acme.json
LIVEKIT_CONFIG_PATH=/data/compose/25/livekit-config.yaml
NGINX_LIVEKIT_CONFIG_PATH=/data/compose/25/nginx-livekit.conf
SESSION_SECRET=your-long-random-string
LIVEKIT_API_KEY=your-key
LIVEKIT_API_SECRET=your-secret
# Production settings
NODE_ENV=production
HTTPS=true
APP_URL=https://app.yourdomain.com
# Optional - Email (for meeting invitations)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_SECURE=true
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
EMAIL_FROM="PeerWave" <noreply@yourdomain.com>
# Optional - Admin users
ADMIN_EMAILS=admin@example.com# Linux/macOS
openssl rand -base64 32
# Windows PowerShell
[Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))Important: The LIVEKIT_API_KEY and LIVEKIT_API_SECRET in your .env file must match the keys in livekit-config.yaml:
# livekit-config.yaml
keys:
your-api-key-here: your-api-secret-hereBoth must use the same values for authentication to work.
Download pre-built native clients from GitHub Releases:
- Windows:
.exeinstaller or portable.zip - Android:
.apk - macOS:
.dmginstaller (coming soon) - Linux: AppImage (coming soon)
Windows:
cd client
flutter build windows --releaseAndroid:
cd client
flutter build apk --release --split-per-abiSee ANDROID_BUILD.md for detailed Android build instructions.
macOS:
flutter build macos --releaseLinux:
flutter build linux --release- Generate new
SESSION_SECRET(min 32 chars):openssl rand -base64 32 - Generate new
LIVEKIT_API_KEY:openssl rand -base64 32 - Generate new
LIVEKIT_API_SECRET:openssl rand -base64 32 - Never use
devkeyorsecretin production - Setup TLS certificates for LiveKit TURN (see CERTIFICATES.md)
- Set
NODE_ENV=production - Configure
LIVEKIT_TURN_DOMAINwith your domain - Set up email (SMTP) for meeting invitations
- Configure
CORS_ORIGINSfor your domain(s) - Review and adjust
livekit-config.yamlport ranges - Verify TURN server connectivity with trickle-ice
| Port | Protocol | Service | Purpose |
|---|---|---|---|
| 3000 | TCP | Web/API Server | Main application |
| 7880 | TCP | LiveKit WebSocket | WebRTC signaling |
| 7881 | TCP | LiveKit HTTP API | Internal API |
| 443 | UDP | TURN/UDP (QUIC) | P2P NAT traversal |
| 5349 | TCP/UDP | TURN/TLS | Firewall-friendly P2P |
| 30100-30200 | UDP | RTP Media | WebRTC audio/video |
| 30300-30400 | UDP | TURN Relay | P2P relay ports |
| Port | Protocol | Service | Purpose | Notes |
|---|---|---|---|---|
| 80 | TCP | HTTP | Redirect to HTTPS | Traefik managed |
| 443 | TCP | HTTPS | Web/API Server | Traefik managed |
| 7880 | TCP | LiveKit WS | WebRTC signaling | Via nginx proxy |
| 443 | UDP | TURN/UDP | P2P traversal | Direct to LiveKit |
| 5349 | TCP/UDP | TURN/TLS | Firewall-friendly | Direct to LiveKit |
| 30100-30200 | UDP | RTP Media | WebRTC streams | Direct to LiveKit |
| 30300-30400 | UDP | TURN Relay | P2P relay | Direct to LiveKit |
Architecture Notes:
- Traefik manages HTTPS (port 443 TCP) and routes to nginx proxy
- nginx proxy (bridge network) forwards WebSocket to LiveKit (host network)
- LiveKit uses host networking due to VPS limitations with UDP port ranges
- Direct UDP ports (443, 5349, 30100-30400) bind to host for WebRTC traffic
VPS Compatibility: If your VPS doesn't support bridge networking with UDP ports, this configuration uses host networking for LiveKit while keeping other services on bridge networks.
For common issues and solutions, see TROUBLESHOOTING.md.
VPS-Specific Issues:
- Bridge networking fails with UDP ports → Use host networking (already configured in docker-compose.traefik.yml)
- 502 Bad Gateway with LiveKit → Check nginx-livekit.conf uses
172.17.0.1:7880 host.docker.internaldoesn't work on Linux → Use Docker bridge gateway IP
Quick diagnostics:
# Check all services are running
docker-compose ps
# View logs
docker-compose logs --tail=50
# Test connectivity
curl -I http://localhost:3000PeerWave is free and open source software licensed under AGPL-3.0.
- ✅ Use for any purpose (personal, commercial, internal)
- ✅ View, study, and modify source code
- ✅ Deploy and host yourself
- ✅ Community support
- ✅ Self-service updates
- Priority technical support
- Managed updates and security patches
- Compiled application binaries
- Email support with SLA
- Optional managed hosting services
For pricing and subscription details, visit: https://peerwave.org
Contact for support inquiries:
📧 license@peerwave.org
This project is licensed under the GNU Affero General Public License v3.0
See LICENSE for full details.
"PeerWave" is a trademark of PeerWave Labs (Simon Zander). Use of the AGPL-3.0 licensed code does not grant trademark rights. Modified versions must be rebranded.