| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| computing:element-call [2026/10/10 05:39] – oemb1905 | computing:element-call [2026/10/10 06:03] (current) – oemb1905 |
|---|
| ==== 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 |
| </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> |
| |
| ==== 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> |
| 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 |
| </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 |
| </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> |
| 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 |
| </code> | </code> |
| |
| ''/etc/apache2/sites-available/webrtc.gnulinux.club.conf'': | Inside ''nano /etc/apache2/sites-available/webrtc.gnulinux.club.conf'': |
| |
| <code> | <code> |
| 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 |
| </VirtualHost> | </VirtualHost> |
| </code> | </code> |
| | |
| | Once that's done, let's enable them and check the endpoints: |
| |
| <code> | <code> |
| |
| ==== 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> |
| 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> |
| </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> |
| </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> |
| } | } |
| </code> | </code> |
| | |
| | Reload service and check API endpoint: |
| |
| <code> | <code> |
| |
| ==== 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> |
| </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// |