Files
computer-playbook/roles/web-app-jitsi/meta/services.yml
kevinveenbirkenbachandClaude Opus 5.5 9b88fccfc6 fix(web-app-matrix): wire Jitsi, Element Call and Heisenbridge in the ansible flavor
An earlier commit on this branch turned the three off because the ansible flavor ran
them without a published port, proxy entry, domain or certificate. They
now stay on and are wired end to end.

Element Call: MDAD's LiveKit server and JWT service get their own
entities in meta/services.yml with resource limits, local ports and a
public media port (TCP and UDP). The runner container publishes them
through container_ports, and the Synapse vhost proxies /livekit-server/
(websocket) and /livekit-jwt-service/ to them. The JWT service checks
each OpenID token against the user's homeserver over federation, and
federation was not reachable in this flavor: Synapse served it only on
a plain-HTTP listener that the runner published directly on 8448.
Synapse now serves the client and federation resources on one listener,
OpenResty serves the Synapse vhost on 443 and as default_server on the
federation port, the direct 8448 publish is gone, and the role writes
/.well-known/matrix/server as the compose flavor does. With a
self-signed CA the JWT container mounts the CA bundle as Synapse does.

Jitsi: a new services.jitsi entity follows the shared-service contract.
It is enabled in the ansible flavor off tor nodes. When web-app-jitsi is
in the inventory, Element points at that shared Jitsi and MDAD's own
Jitsi stays off. Otherwise MDAD runs its own Jitsi on jitsi.<domain>
with a front-proxy vhost, its web port published to the runner and its
videobridge on a public UDP port. The entity lists the jitsi domain, so
the web health probe skips it whenever Matrix does not serve it. The
jitsi_*_container_network overrides were dropped: MDAD reads none of
them, Jitsi always ran on its own network. Variant 0 covers the shared
case, variant 1 the internal one. On an onion-primary deploy both call
stacks stay off, so Element never advertises a clearnet call surface.
MDAD's Prosody keeps an account's first password, so after a credential
rotation jicofo failed SASL with the new one. The role now derives the
jicofo and videobridge passwords from the macaroon secret and recreates
both accounts on every deploy.

Heisenbridge stays on by default. It runs in the nested host network,
where MDAD's container-name URLs do not resolve, so its homeserver URL
and the appservice URL in its registration point at 127.0.0.1.

A bootstrap that a previous deploy left failed (for example after a
Docker Hub rate limit) is now reset and restarted, so a mode=update
deploy converges instead of failing on the stale unit state.

Playwright proves each path: the RTC spec fetches a LiveKit token from
the JWT service and opens the SFU signalling websocket, the Jitsi spec
checks Element's preferred domain and joins a conference (signing in
through Keycloak first when the shared Jitsi sits behind SSO), and the
Heisenbridge spec opens a DM with the bot and waits for its answer to
"help".

Closes #1165

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 17:16:20 +02:00

129 lines
3.5 KiB
YAML

---
sso:
bond: 1
enabled: "{{ 'web-app-keycloak' in group_names }}"
shared: "{{ 'web-app-keycloak' in group_names }}"
flavor: oauth2
oauth2:
origin:
host: web
port: 80
ldap:
bond: 1
enabled: "{{ 'svc-db-openldap' in group_names }}"
shared: "{{ 'svc-db-openldap' in group_names }}"
logout:
bond: 1
enabled: "{{ 'web-svc-logout' in group_names }}"
shared: "{{ 'web-svc-logout' in group_names }}"
dashboard:
bond: 1
enabled: "{{ 'web-app-dashboard' in group_names }}"
shared: "{{ 'web-app-dashboard' in group_names }}"
matomo:
bond: 1
enabled: "{{ 'web-app-matomo' in group_names }}"
shared: "{{ 'web-app-matomo' in group_names }}"
prometheus:
bond: 1
enabled: "{{ 'web-app-prometheus' in group_names }}"
shared: "{{ 'web-app-prometheus' in group_names }}"
# nocheck: playwright-service-flag - email not used by Jitsi room flow
email:
bond: 1
enabled: "{{ MAIL_PROVIDER in group_names }}"
shared: "{{ MAIL_PROVIDER in group_names }}"
# nocheck: playwright-service-flag - css consumer, no Playwright surface (provider: web-svc-css)
css:
bond: 1
enabled: "{{ 'web-svc-css' in group_names }}"
shared: "{{ 'web-svc-css' in group_names }}"
# nocheck: dynamic-flag - gated on services.sso.enabled, not on group_names
# nocheck: playwright-service-flag - runtime DOM patch, no probe-able surface flag
javascript:
bond: 1
enabled: "{{ lookup('config', 'web-app-jitsi', 'services.sso.enabled') | bool }}"
shared: "{{ lookup('config', 'web-app-jitsi', 'services.sso.enabled') | bool }}"
# nocheck: playwright-service-flag: shared provider entity; the app itself is covered by this role's own Playwright spec
jitsi:
healthcheck:
flavor: tcp
modes:
compose:
enabled: true
swarm:
enabled: true
bond: 1
enabled: true
shared: true
image: jitsi/web
version: "stable-11031"
min_storage: 315MB
# nocheck: default-placement-manager meta/volumes.yml uses type:bind config dirs staged on the stack host; a worker-scheduled task lacks the source paths (unpinning requires migrating them to nfs-backed named volumes)
placement: manager
ports:
local:
http: 8084
sso: 16505
public:
media: 10000
internal:
http: 80
proxy:
service_key: web
run_after:
- web-app-keycloak
lifecycle: beta
cpus: "2.0"
mem_reservation: 1g
mem_limit: 3g
pids_limit: 2048
web:
name: jitsi-web
cpus: "0.5"
mem_reservation: 128m
mem_limit: 512m
pids_limit: 512
# nocheck: playwright-service-flag - internal sub-component (XMPP server, not a user-facing surface)
prosody:
healthcheck:
flavor: tcp
port_key: http
name: jitsi-prosody
image: jitsi/prosody
version: "stable-11031"
ports:
internal:
xmpp: 5222
component: 5347
http: 5280
cpus: "1.0"
mem_reservation: 512m
mem_limit: 1g
pids_limit: 1024
# nocheck: playwright-service-flag - internal sub-component (conference focus)
# nocheck: image-healthcheck XMPP component, no internal port declared
jicofo:
name: jitsi-jicofo
image: jitsi/jicofo
version: "stable-11031"
cpus: "1.0"
mem_reservation: 512m
mem_limit: 1g
pids_limit: 1024
# nocheck: playwright-service-flag - internal sub-component (video bridge, media plane)
# nocheck: image-healthcheck media bridge on UDP, no internal port declared
jvb:
name: jitsi-jvb
image: jitsi/jvb
version: "stable-11031"
cpus: "2.0"
mem_reservation: 1g
mem_limit: 2g
pids_limit: 2048
# nocheck: playwright-service-flag
tor:
enabled: false # nocheck: dynamic-flag
shared: false # nocheck: dynamic-flag