From 60a7385b769289b7297fbbacace7d1fed9134e92 Mon Sep 17 00:00:00 2001 From: Enmanuel Date: Tue, 11 Nov 2025 00:54:43 +0000 Subject: [PATCH] =?UTF-8?q?livekit=20a=C3=B1adido?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configs/nginx/matrix-rtc-proxy.conf | 16 ++++++- configs/nginx/well-known.conf | 55 ++++++++++++++++++++++++ configs/well-known/matrix-server.json | 3 ++ docker-compose.livekit.yml | 25 ++++------- docker-compose.yml | 19 ++++++++ docs/livekit-deployment.md | 52 ++++++++++++++++++++++ element-config.json | 26 +++++++++-- element-web-custom/hide-legacy-calls.css | 10 +++++ 8 files changed, 184 insertions(+), 22 deletions(-) create mode 100644 configs/nginx/well-known.conf create mode 100644 configs/well-known/matrix-server.json create mode 100644 docs/livekit-deployment.md create mode 100644 element-web-custom/hide-legacy-calls.css diff --git a/configs/nginx/matrix-rtc-proxy.conf b/configs/nginx/matrix-rtc-proxy.conf index e1d4053..7511326 100644 --- a/configs/nginx/matrix-rtc-proxy.conf +++ b/configs/nginx/matrix-rtc-proxy.conf @@ -1,6 +1,14 @@ server { listen 80; - server_name matrix-rtc.localhost; + server_name _; + + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; + add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization" always; + + if ($request_method = OPTIONS) { + return 204; + } # MatrixRTC Authorization Service (lk-jwt-service) location ^~ /livekit/jwt/ { @@ -8,6 +16,9 @@ server { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; + add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization" always; proxy_pass http://livekit-jwt:6080/; } @@ -21,6 +32,9 @@ server { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Accept-Encoding gzip; + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; + add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization" always; proxy_send_timeout 120; proxy_read_timeout 120; diff --git a/configs/nginx/well-known.conf b/configs/nginx/well-known.conf new file mode 100644 index 0000000..1be5b7c --- /dev/null +++ b/configs/nginx/well-known.conf @@ -0,0 +1,55 @@ +server { + listen 80; + server_name _; + + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; + add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization" always; + + if ($request_method = OPTIONS) { + return 204; + } + + # Serve Matrix well-known documents + location /.well-known/matrix/client { + default_type application/json; + alias /var/www/well-known/matrix-client.json; + add_header Access-Control-Allow-Origin * always; + try_files $uri =404; + } + + location /.well-known/matrix/server { + default_type application/json; + alias /var/www/well-known/matrix-server.json; + add_header Access-Control-Allow-Origin * always; + try_files $uri =404; + } + + # MatrixRTC Authorization Service (lk-jwt-service) + location ^~ /livekit/jwt/ { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://livekit-jwt:8080/; + } + + # LiveKit SFU Websocket (signalling) + location ^~ /livekit/sfu/ { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Accept-Encoding gzip; + proxy_http_version 1.1; + proxy_send_timeout 120; + proxy_read_timeout 120; + proxy_buffering off; + proxy_pass http://livekit:7880/; + } + + location / { + return 404; + } +} diff --git a/configs/well-known/matrix-server.json b/configs/well-known/matrix-server.json new file mode 100644 index 0000000..abdc226 --- /dev/null +++ b/configs/well-known/matrix-server.json @@ -0,0 +1,3 @@ +{ + "m.server": "matrix-af2f3d.organic-machine.com:443" +} diff --git a/docker-compose.livekit.yml b/docker-compose.livekit.yml index 756d951..c74f107 100644 --- a/docker-compose.livekit.yml +++ b/docker-compose.livekit.yml @@ -12,10 +12,12 @@ services: - "${LIVEKIT_UDP_PORT_RANGE_START:-50000}-${LIVEKIT_UDP_PORT_RANGE_END:-50200}:${LIVEKIT_UDP_PORT_RANGE_START:-50000}-${LIVEKIT_UDP_PORT_RANGE_END:-50200}/udp" networks: default: - ipv4_address: 10.10.10.6 + ipv4_address: 10.10.10.10 + extra_hosts: + - "matrix-rtc-320bd4.organic-machine.com:10.10.10.6" livekit-jwt: - image: ghcr.io/element-hq/lk-jwt-service:latest-ci + image: ghcr.io/element-hq/lk-jwt-service:latest restart: unless-stopped environment: LIVEKIT_JWT_BIND: ${LIVEKIT_JWT_BIND:-:6080} @@ -26,21 +28,10 @@ services: LIVEKIT_INSECURE_SKIP_VERIFY_TLS: ${LIVEKIT_INSECURE_SKIP_VERIFY_TLS:-false} networks: default: - ipv4_address: 10.10.10.7 - - matrix-rtc-proxy: - image: nginx:alpine - restart: unless-stopped - depends_on: - - livekit - - livekit-jwt - volumes: - - ./configs/nginx/matrix-rtc-proxy.conf:/etc/nginx/conf.d/default.conf:ro - ports: - - "${LIVEKIT_JWT_PORT:-6080}:80" - networks: - default: - ipv4_address: 10.10.10.9 + ipv4_address: 10.10.10.11 + extra_hosts: + - "matrix-af2f3d.organic-machine.com:10.10.10.6" + - "matrix-rtc-320bd4.organic-machine.com:10.10.10.6" networks: default: diff --git a/docker-compose.yml b/docker-compose.yml index 6071773..da6cb5d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,6 +51,25 @@ services: depends_on: - synapse + wellknown: + image: nginx:alpine + restart: unless-stopped + networks: + default: + ipv4_address: 10.10.10.12 + volumes: + - ./configs/well-known:/var/www/well-known:ro + - ./configs/nginx/well-known.conf:/etc/nginx/conf.d/default.conf:ro + + element-call-web: + image: nginx:alpine + restart: unless-stopped + networks: + default: + ipv4_address: 10.10.10.13 + volumes: + - ./element-call/dist:/usr/share/nginx/html:ro + volumes: matrix_postgres_data: external: true diff --git a/docs/livekit-deployment.md b/docs/livekit-deployment.md new file mode 100644 index 0000000..4241d5f --- /dev/null +++ b/docs/livekit-deployment.md @@ -0,0 +1,52 @@ +# Element Call + LiveKit Deployment Notes + +Resumen rápido de los pasos que seguimos para que Element Web use LiveKit como backend: + +1. **Synapse listo para MatrixRTC** + - Listener HTTP con `resources: [client, federation, openid]`. + - Flags `experimental_features` (MSC3266/4222/4354), `max_event_delay_duration`, `rc_message` y `rc_delayed_event_mgmt` activados. + - Reinicio de `synapse` tras editar `synapse_data/homeserver.yaml`. + +2. **Stack base en Docker** + - `docker-compose.yml` levanta Synapse, Element Web, Synapse Admin y el proxy `wellknown` (Nginx). + - El proxy sirve `/.well-known/...` y ahora también enruta `/livekit/jwt` y `/livekit/sfu`. + +3. **Servicios LiveKit** + - `docker-compose.livekit.yml` inicia `livekit` y `livekit-jwt`. + - `configs/livekit/livekit.yaml` define puertos, región y las claves `LIVEKIT_API_KEY/SECRET`. + - `extra_hosts` para que `livekit` y `livekit-jwt` resuelvan `matrix-af2f3d...` y `matrix-rtc-320bd4...` al Traefik interno (`10.10.10.6`). + +4. **Traefik / Coolify** + - Routers para: + - `element-a05ae4...` → contenedor Element Web. + - `matrix-af2f3d...` → Synapse + `/.well-known`. + - `matrix-rtc-320bd4...` → Nginx (`wellknown`) que reenvía a `livekit-jwt` y `livekit`. + - `call-681f3d...` → frontend Element Call (`element-call-web`). + - Middleware de redirección HTTPS y CORS (solo se permite `https://element-a05ae4...`). + +5. **Element Call frontend** + - En `element-call/`: configuramos `config/config.organic-machine.json`, copiamos a `public/config.json` y ejecutamos `yarn install`, `yarn build`. + - El servicio `element-call-web` (Nginx) sirve `element-call/dist` y se expone como `https://call-681f3d.organic-machine.com`. + +6. **Element Web** + - `element-config.json` habilita los labs (`feature_group_calls`, `feature_element_call_video_rooms`, etc.) y define `element_call.url` → `https://call-681f3d...`. + - Reiniciamos el contenedor para que sirviera el nuevo `config.json`. + +7. **CORS y salud** + - Nginx responde 204 a los preflight y añade las cabeceras `Access-Control-Allow-*`. + - Traefik refuerza CORS para que solo el origen de Element Web pueda usar `/livekit/jwt` y `/livekit/sfu`. + - `livekit-jwt` valida tokens OpenID contra Synapse y crea salas vía Twirp en LiveKit. + +8. **Dominios implicados** + - `matrix-af2f3d.organic-machine.com` – Synapse y `.well-known`. + - `element-a05ae4.organic-machine.com` – Element Web. + - `admin-0cc4d3.organic-machine.com` – Synapse Admin. + - `call-681f3d.organic-machine.com` – Element Call frontend. + - `matrix-rtc-320bd4.organic-machine.com` – LiveKit JWT + SFU. + +9. **Diagnóstico rápido** + - `sudo docker compose -f docker-compose.livekit.yml logs -f livekit-jwt livekit` – tokens y salas. + - `sudo docker compose logs synapse | grep openid` – emisión de OpenID. + - DevTools → Network → `livekit/jwt/sfu/get` – debe responder 200 con CORS correcto. + +Con todo esto, Element Web usa Element Call (widget) y LiveKit como backend SFU. diff --git a/element-config.json b/element-config.json index 10f029b..e265f79 100644 --- a/element-config.json +++ b/element-config.json @@ -15,12 +15,17 @@ "feature_custom_tags": true, "feature_state_counters": true, "feature_user_directory": true, - "feature_explore_rooms": true + "feature_explore_rooms": true, + "feature_group_calls": true, + "feature_video_rooms": true, + "feature_element_call_video_rooms": true }, "default_federate": false, "default_theme": "light", "room_directory": { - "servers": ["matrix-af2f3d.organic-machine.com"] + "servers": [ + "matrix-af2f3d.organic-machine.com" + ] }, "enable_presence_by_hs_url": { "https://matrix-af2f3d.organic-machine.com": true @@ -32,9 +37,22 @@ "brand_image_url": "", "welcomeUserId": "@welcome-bot:matrix-af2f3d.organic-machine.com", "roomDirectory": { - "servers": ["matrix-af2f3d.organic-machine.com"], + "servers": [ + "matrix-af2f3d.organic-machine.com" + ], "include_all_known_servers": false }, "permalink_prefix": "https://element-a05ae4.organic-machine.com", - "bug_report_endpoint_url": "" + "bug_report_endpoint_url": "", + "setting_defaults": { + "feature_group_calls": true, + "feature_video_rooms": true, + "feature_element_call_video_rooms": true, + "hideCallButtonsInComposer": true + }, + "element_call": { + "url": "https://call-681f3d.organic-machine.com/", + "participant_limit": 16, + "brand": "Element Call" + } } diff --git a/element-web-custom/hide-legacy-calls.css b/element-web-custom/hide-legacy-calls.css new file mode 100644 index 0000000..fed0650 --- /dev/null +++ b/element-web-custom/hide-legacy-calls.css @@ -0,0 +1,10 @@ +/* Hide legacy (1:1) call entry points, keeping only Element Call buttons */ +button[aria-label*="voice call" i], +button[aria-label*="video call" i], +button[aria-label*="llamada" i], +button[aria-label*="videollamada" i], +.mx_MessageComposer_buttonCall, +.mx_MessageComposer_buttonGroup .mx_MessageComposer_button:nth-child(3), +.mx_MessageComposer_buttonGroup .mx_MessageComposer_button:nth-child(4) { + display: none !important; +}