User Tools

Site Tools


computing:element-call

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
computing:element-call [2026/10/10 01:09] – oemb1905computing:element-call [2026/10/10 06:03] (current) – oemb1905
Line 14: Line 14:
  
 ==== Introduction ==== ==== Introduction ====
-Rootless Podman as user ''worker'' on host ''support'' (''8.28.86.82'', ''2604:fa40:0:10::9''). Apache terminates TLS for the two HTTP names. The containers speak plain HTTP on localhost. TURN is UDP on 3479. Talk keeps 3478. Apache keeps TCP 443. Synapse stays on the Matrix VM.+ 
 +This tutorial is for Debian users who already self-host Matrix-Synapse and need to build an Element Call instance to support it with. Now, in my case, I manually self-host [[https://wiki.haacksnetworking.org/doku.php?id=computing:synapse|Matrix-Synapse]]. But/and, when I built this instance, Element Call did not exist - Jitsi was not only an add-on, but the standard. Over time, that changed, but/and I had never set it up. I eventually got to it about a year ago and then again about 8 months ago, but failed both times. Manual installation has proven difficult. Given I had recently setup my new virtual docker/OCI host, I thought this might be a perfect use-case for it. Here's the overall layout of what I came up with:
  
 ^ Name ^ Container ^ Bind ^ Public ^ ^ Name ^ Container ^ Bind ^ Public ^
Line 25: Line 26:
 | TURN relay | same | ''35000-35100/udp'' | that range | | TURN relay | same | ''35000-35100/udp'' | that range |
  
-Do not use 8080, 8082, 8088, 3478, or 443.+Since this was the 4th container on the same instance, I need to avoid using ports 8080, 8082, 8088, 3478, and 443. I just used 3479 instead, since HPB was already using 3478. The main proxy port was also easy to adjust. 
  
 Images: Images:
Line 32: Line 33:
   * ''ghcr.io/element-hq/lk-jwt-service:latest''   * ''ghcr.io/element-hq/lk-jwt-service:latest''
   * ''docker.io/livekit/livekit-server:latest''   * ''docker.io/livekit/livekit-server:latest''
- 
-Do not use ''podman generate systemd''. Units come from Quadlet files in ''~/.config/containers/systemd/''. 
  
 ==== 1. DNS ==== ==== 1. DNS ====
-''call.gnulinux.club'' and ''webrtc.gnulinux.club'' → ''8.28.86.82'' and ''2604:fa40:0:10::9''.+ 
 +Set your A/AAAA records to point at the virtual machine / OCI container host. The reverse proxy we set up later will handle the rest. 
  
 ==== 2. Firewall (root) ==== ==== 2. Firewall (root) ====
 +
 +Here's the ufw rules I came up with:
 +
 <code> <code>
-ufw allow 3479/udp comment 'Element Call TURN UDP' +ufw allow 3479/udp 
-ufw allow 35000:35100/udp comment 'Element Call TURN relay' +ufw allow 35000:35100/udp 
-ufw allow 7881/tcp comment 'Element Call ICE TCP' +ufw allow 7881/tcp 
-ufw allow 50100:50200/udp comment 'Element Call ICE UDP'+ufw allow 50100:50200/udp
 </code> </code>
  
 ==== 3. Secret (worker) ==== ==== 3. Secret (worker) ====
 +
 +Let's get the secrets cut:
 +
 <code> <code>
 mkdir -p ~/element-call mkdir -p ~/element-call
Line 54: Line 60:
 </code> </code>
  
-Key name: ''matrixrtc''. Placeholder used below:+==== 4. Certificates (root) ====
  
-<code> +After the key and project directory are ready, we can cut the cert:
-LIVEKIT_SECRET=replace-with-your-livekit-secret +
-</code>+
  
-==== 4. Certificates (root) ==== 
 <code> <code>
 certbot certonly --apache -d call.gnulinux.club -d webrtc.gnulinux.club certbot certonly --apache -d call.gnulinux.club -d webrtc.gnulinux.club
 a2enmod proxy proxy_http proxy_wstunnel headers rewrite ssl a2enmod proxy proxy_http proxy_wstunnel headers rewrite ssl
 </code> </code>
- 
-Apache is the only process that reads these. 
  
 ==== 5. LiveKit config (worker) ==== ==== 5. LiveKit config (worker) ====
 +
 +Let's pull the images and create our configuration files:
 +
 <code> <code>
 +podman pull ghcr.io/element-hq/element-call:v0.26.1
 +podman pull ghcr.io/element-hq/lk-jwt-service:latest
 +podman pull docker.io/livekit/livekit-server:latest
 +
 cat > ~/element-call/livekit.yaml << 'EOF' cat > ~/element-call/livekit.yaml << 'EOF'
 port: 7880 port: 7880
Line 100: Line 108:
 </code> </code>
  
-''node_ip'' is the public IPv4 clients use for media. It does not take Apache's TCP 443. ''auto_create: false'' is required. The JWT service creates rooms.+Make sure ''auto_create: false'' is declared - The JWT service creates rooms.
  
 ==== 6. Element Call config (worker) ==== ==== 6. Element Call config (worker) ====
-The image serves files from ''/app''. A mount on ''/usr/share/nginx/html'' is ignored. The file must exist before the container starts, or Podman creates a directory and nginx falls through to ''index.html''.+ 
 +The image serves files from ''/app''. A mount on ''/usr/share/nginx/html'' is ignored. The file must exist before the container starts, or Podman creates a directory and nginx falls through to ''index.html''. On the VM, establish the endpoint:
  
 <code> <code>
Line 125: Line 134:
  
 ==== 7. Quadlets ==== ==== 7. Quadlets ====
-''lk-jwt'' must resolve ''webrtc.gnulinux.club'' to the host. Without ''AddHost'', room creation hairpins to the public IP and gets connection refused. ''LIVEKIT_FULL_ACCESS_HOMESERVERS'' is ''gnulinux.club'', not ''matrix.gnulinux.club''.+ 
 +Also on the VM, make sure the quadlet is setup. You should note that ''lk-jwt'' must resolve ''webrtc.gnulinux.club'' which is the host. Without ''AddHost'', room creation hairpins to the public IP and gets connection refused so we define the hostname inside the container with an extra line to address this failure. The other thing is ''LIVEKIT_FULL_ACCESS_HOMESERVERS'' is ''gnulinux.club'', not ''matrix.gnulinux.club''.
  
 <code> <code>
Line 194: Line 204:
 systemctl --user start container-element-call.service systemctl --user start container-element-call.service
 </code> </code>
- 
-''WantedBy=default.target'' starts them. Do not ''systemctl enable'' a Quadlet unit. Do not ''podman generate systemd''. 
  
 ==== 8. Verify ==== ==== 8. Verify ====
 +
 +Let's make sure those quadlets all function:
 +
 <code> <code>
 systemctl --user is-active container-livekit.service container-lk-jwt.service container-element-call.service systemctl --user is-active container-livekit.service container-lk-jwt.service container-element-call.service
Line 206: Line 217:
 </code> </code>
  
-Expect ''active'' on all three. ''config.json'' must be JSON, not the HTML page. LiveKit should log ''turn.portUDP'' 3479, ''relay_range_start'' 35000, and ''nodeIP'' ''8.28.86.82''.+Here, we are looking for ''active'' on all three and ''config.json'' must be JSON, not the HTML page. LiveKit should log ''turn.portUDP'' 3479, ''relay_range_start'' 35000, and ''nodeIP'' ''8.28.86.82'' and/or the instance's IP.
  
 ==== 9. Upgrade script ==== ==== 9. Upgrade script ====
-''/usr/local/bin/upgrade-element-call.sh''. A tag change is an edit to ''Image='' in the matching ''.container'' file before ''daemon-reload''. The script does not recreate the units.+ 
 +Here's a simple upgrade script for the OCI container. Create ''nano /usr/local/bin/upgrade-element-call.sh''. In that file, place:
  
 <code> <code>
 #!/bin/bash #!/bin/bash
 set -euo pipefail set -euo pipefail
 +export XDG_RUNTIME_DIR=/run/user/$(id -u)
 +export DBUS_SESSION_BUS_ADDRESS=unix:path=${XDG_RUNTIME_DIR}/bus
  
 podman pull docker.io/livekit/livekit-server:latest podman pull docker.io/livekit/livekit-server:latest
Line 235: Line 249:
 </code> </code>
  
-Run it as ''worker'':+==== 10. Apache (root) ====
  
-<code> +Now that the service is created and running, make sure dns for a/aaaa is ready and then let's cut the cert.
-su - worker -c '/bin/bash /usr/local/bin/upgrade-element-call.sh' +
-</code>+
  
-Do not ''sudo -u worker''. That drops the session bus.+  sudo certbot certonly --apache -d call.gnulinux.club 
 +  sudo certbot certonly --apache -d webrtc.gnulinux.club
  
-==== 10. Apache (root) ==== +We also need to create the reverse proxy so we can forward external requests upstream to the local listening services we just created. For the cert(s) ''nano /etc/apache2/sites-available/call.gnulinux.club.conf'' and drop in:
-''/etc/apache2/sites-available/call.gnulinux.club.conf'':+
  
 <code> <code>
Line 252: Line 264:
     RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]     RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
 </VirtualHost> </VirtualHost>
 +</code>
  
 +Inside ''nano /etc/apache2/sites-available/call.gnulinux.club-ssl.conf'' something like:
 +
 +<code>
 <VirtualHost *:443> <VirtualHost *:443>
     ServerName call.gnulinux.club     ServerName call.gnulinux.club
Line 266: Line 282:
 </code> </code>
  
-''/etc/apache2/sites-available/webrtc.gnulinux.club.conf'':+Inside ''nano /etc/apache2/sites-available/webrtc.gnulinux.club.conf'':
  
 <code> <code>
Line 274: Line 290:
     RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]     RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
 </VirtualHost> </VirtualHost>
 +</code>
  
 +Inside ''nano /etc/apache2/sites-available/webrtc.gnulinux.club-ssl.conf'':
 +
 +<code>
 <VirtualHost *:443> <VirtualHost *:443>
     ServerName webrtc.gnulinux.club     ServerName webrtc.gnulinux.club
Line 294: Line 314:
 </VirtualHost> </VirtualHost>
 </code> </code>
 +
 +Once that's done, let's enable them and check the endpoints:
  
 <code> <code>
Line 306: Line 328:
  
 ==== 11. Synapse (Matrix VM) ==== ==== 11. Synapse (Matrix VM) ====
-No new ports. Existing HTTPS is enough. Append this at the bottom of ''/etc/matrix-synapse/homeserver.yaml'', same indent as ''pid_file''. Do not nest it under ''email'' or ''database''.+ 
 +On the Matrix VM, we need to edit ''nano /etc/matrix-synapse/homeserver.yaml'':
  
 <code> <code>
Line 329: Line 352:
       livekit_service_url: "https://webrtc.gnulinux.club/livekit/jwt"       livekit_service_url: "https://webrtc.gnulinux.club/livekit/jwt"
 </code> </code>
 +
 +Then, restart the service:
  
 <code> <code>
Line 334: Line 359:
 </code> </code>
  
-Wait until it is active. A curl during those few seconds returns nginx 502. The LiveKit secret is not added here. Synapse only advertises the JWT URL. ''lk-jwt'' checks the OpenID token. +You can test with:
- +
-This Synapse serves the unstable route only. ''/_matrix/client/v1/rtc/transports'' returns ''M_UNRECOGNIZED''. Element Call uses the unstable route. That is expected. +
- +
-With a real Element access token:+
  
 <code> <code>
Line 345: Line 366:
 </code> </code>
  
-The body must contain ''https://webrtc.gnulinux.club/livekit/jwt''.+The body of the output should contain ''https://webrtc.gnulinux.club/livekit/jwt''.
  
 ==== 12. Well-known (Matrix VM) ==== ==== 12. Well-known (Matrix VM) ====
-''/var/www/gnulinux.club/.well-known/matrix/client'' must be valid JSON. No ''#'' comments. A comment makes Element fail parse and show ''MISSING_MATRIX_RTC_TRANSPORT''.+ 
 +In an initial build, I left old comments/notes inside ''nano /var/www/gnulinux.club/.well-known/matrix/client'' commented out at the end, but the API parser can't handle comments. Everything - literally - must be valid JSON. The comments made Element fail and show ''MISSING_MATRIX_RTC_TRANSPORT''. The new ''nano /var/www/gnulinux.club/.well-known/matrix/client'' should look like:
  
 <code> <code>
Line 377: Line 399:
 } }
 </code> </code>
 +
 +Reload service and check API endpoint:
  
 <code> <code>
Line 384: Line 408:
  
 ==== 13. Element Web ==== ==== 13. Element Web ====
-In ''element.gnulinux.club'' ''config.json'', replace the hosted call URL:+ 
 +In ''element.gnulinux.club'' ''config.json'', replace the hosted call URL block with the following:
  
 <code> <code>
Line 395: Line 420:
 </code> </code>
  
-''https://call.element.io'' shows ''MISSING_MATRIX_RTC_TRANSPORT'' even when Synapse is correct. Hard-refresh after the change. +That should be it. Debug and review line by line if stuff is failing. Reach out on Matrix if needed.
- +
-==== Facts ==== +
-  * UD+
  
- --- //[[alerts@haacksnetworking.org|oemb1905]] 2026/10/10 01:06//+ --- //[[alerts@haacksnetworking.org|oemb1905]] 2026/10/10 05:54//
computing/element-call.1791594542.txt.gz · Last modified: by oemb1905