Files
homelab-optimized/docs/services/individual/matrixrtc-livekit.md
Gitea Mirror Bot e7652c8dab
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m3s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-20 01:32:01 UTC
2026-04-20 01:32:01 +00:00

163 lines
5.4 KiB
Markdown

# MatrixRTC / LiveKit — Element X Calls
**Last updated:** 2026-03-19
MatrixRTC enables voice/video calls in Element X using a LiveKit SFU backend. Both homeservers (`mx.vish.gg` and `matrix.thevish.io`) share the same LiveKit SFU on `matrix-ubuntu`.
---
## Service Overview
| Property | Value |
|----------|-------|
| **Host** | matrix-ubuntu (`192.168.0.154`) |
| **Matrix homeservers** | `mx.vish.gg` (synapse-mx.service) and `matrix.thevish.io` (synapse.service) — both on Synapse 1.148.0 |
| **Compose file** | `hosts/vms/matrix-ubuntu/livekit.yml` (deployed manually at `/opt/livekit/`) |
| **LiveKit version** | 1.9.12 |
| **JWT service** | `ghcr.io/element-hq/lk-jwt-service:latest-ci` |
---
## Architecture
```
Element X ──→ mx.vish.gg (.well-known) ──→ livekit.mx.vish.gg/livekit/jwt (JWT service)
──→ matrix.thevish.io (.well-known) ──→ livekit.mx.vish.gg/livekit/sfu (LiveKit SFU)
livekit.mx.vish.gg/ (LiveKit WS)
```
Both homeservers share the same LiveKit backend.
- **NPM** on Calypso proxies `livekit.mx.vish.gg` → matrix-ubuntu
- `/livekit/jwt/` → JWT service port 8089 (container 8080)
- `/livekit/sfu/` → LiveKit SFU port 7880
- `/` → LiveKit SFU port 7880 (WebSocket for direct connections)
- **DNS**: `livekit.mx.vish.gg` A record unproxied → `184.23.52.14` (home WAN)
- **TLS**: Let's Encrypt cert issued via Cloudflare DNS challenge on matrix-ubuntu, copied to NPM as `npm-7`
---
## Endpoints
| Endpoint | URL | Purpose |
|----------|-----|---------|
| JWT service healthz | `https://livekit.mx.vish.gg/livekit/jwt/healthz` | Health check |
| JWT service SFU get | `https://livekit.mx.vish.gg/livekit/jwt/sfu/get` | Token exchange |
| LiveKit SFU WS | `wss://livekit.mx.vish.gg/livekit/sfu/` | WebSocket signalling |
| LiveKit HTTP | `https://livekit.mx.vish.gg/` | SFU API |
| .well-known | `https://mx.vish.gg/.well-known/matrix/client` | RTC foci advertisement |
---
## Configuration Files on matrix-ubuntu
| File | Purpose |
|------|---------|
| `/opt/livekit/docker-compose.yml` | LiveKit + JWT service deployment |
| `/opt/livekit/livekit.yaml` | LiveKit SFU config (keys, RTC ports, external IP) |
| `/opt/synapse-mx/homeserver.yaml` | Synapse config (MSCs, rate limits) |
| `/etc/nginx/sites-available/mx-vish-gg` | nginx serving `.well-known` and Element static files |
| `/etc/letsencrypt/live/livekit.mx.vish.gg/` | TLS cert (auto-renews, copies to NPM via deploy hook) |
---
## Synapse homeserver.yaml additions
```yaml
# MatrixRTC / Element Call support
experimental_features:
msc3266_enabled: true # Room Summary API (knocking over federation)
msc4222_enabled: true # state_after in sync v2
msc4140_enabled: true # Delayed events (call participation signalling)
max_event_delay_duration: 24h
rc_message:
per_second: 0.5
burst_count: 30
rc_delayed_event_mgmt:
per_second: 1
burst_count: 20
```
---
## .well-known/matrix/client
Served by nginx at `https://mx.vish.gg/.well-known/matrix/client`:
```json
{
"m.homeserver": {"base_url": "https://mx.vish.gg"},
"org.matrix.msc4143.rtc_foci": [
{
"type": "livekit",
"livekit_service_url": "https://livekit.mx.vish.gg/livekit/jwt"
}
]
}
```
---
## LiveKit SFU config (/opt/livekit/livekit.yaml)
Key settings:
- `use_external_ip: true` — auto-detects WAN IP `184.23.52.14`
- `use_ice_lite: true` — optimised for server-side NAT traversal
- `room.auto_create: false` — only lk-jwt-service creates rooms (security)
- RTC ports: 7880 TCP (API/WS), 7881 TCP (RTC), 50000-60000 UDP (media)
- **Note:** UDP 50000-60000 port range is NOT currently forwarded on the router — TURN relay is used instead via coturn at `turn:mx.vish.gg:3479`
---
## TLS Certificate Renewal
Cert is issued on matrix-ubuntu via certbot + Cloudflare DNS plugin. A deploy hook copies it to NPM on Calypso after renewal:
```
/etc/letsencrypt/renewal-hooks/deploy/copy-to-npm.sh
```
If the hook fails, manually copy:
```bash
ssh matrix-ubuntu
sudo cp /etc/letsencrypt/live/livekit.mx.vish.gg/fullchain.pem \
/tmp/lk.crt
sudo cp /etc/letsencrypt/live/livekit.mx.vish.gg/privkey.pem \
/tmp/lk.key
scp -P 62000 /tmp/lk.crt Vish@100.103.48.78:/volume1/docker/nginx-proxy-manager/data/custom_ssl/npm-7/fullchain.pem
scp -P 62000 /tmp/lk.key Vish@100.103.48.78:/volume1/docker/nginx-proxy-manager/data/custom_ssl/npm-7/privkey.pem
ssh -p 62000 Vish@100.103.48.78 'sudo /usr/local/bin/docker exec nginx-proxy-manager nginx -s reload'
```
---
## Troubleshooting
### Calls not working in Element X
1. Check `.well-known` is advertising foci: `curl https://mx.vish.gg/.well-known/matrix/client`
2. Check JWT service: `curl https://livekit.mx.vish.gg/livekit/jwt/healthz`
3. Check LiveKit is running: `ssh matrix-ubuntu "sudo docker ps | grep livekit"`
4. Check LiveKit logs: `ssh matrix-ubuntu "sudo docker logs livekit 2>&1 | tail -20"`
### Stuck calls
See [How to resolve stuck MatrixRTC calls](https://sspaeth.de/2025/02/how-to-resolve-stuck-matrixrtc-calls/) — usually caused by delayed events not cleaning up.
### JWT service returns 400
Normal for unauthenticated requests. Means the service is running correctly.
### Restarting services
```bash
ssh matrix-ubuntu
cd /opt/livekit
sudo docker compose restart
```
### Restarting Synapse
```bash
ssh matrix-ubuntu
sudo systemctl restart synapse-mx.service
```