diff --git a/hosts/heather/arion-compose.nix b/hosts/heather/arion-compose.nix index bdcaed5..29c278f 100644 --- a/hosts/heather/arion-compose.nix +++ b/hosts/heather/arion-compose.nix @@ -122,6 +122,7 @@ in # Custom network for jitsi (FQDN-based comms, prosody alias xmpp.meet.jitsi) networks.meet-jitsi.driver = "bridge"; + networks.matrix-rtc.driver = "bridge"; services = { # === Forgejo (git.iscg.dev) === # Первый сервис, proof-of-concept для цепочки arion→docker→Caddy. @@ -153,7 +154,7 @@ in # /var/lib/tuwunel-secrets/tuwunel.toml (root:docker 0640, bind-mount ro) # Cinny config: /var/lib/tuwunel-secrets/cinny-config.json (bind-mount ro). tuwunel = { - service.image = "ghcr.io/matrix-construct/tuwunel:v1.9.3"; + service.image = "ghcr.io/matrix-construct/tuwunel:v1.9.4"; service.container_name = "tuwunel"; service.restart = "unless-stopped"; service.volumes = [ @@ -166,6 +167,51 @@ in TUWUNEL_CONFIG = "/etc/tuwunel/tuwunel.toml"; }; }; + # MatrixRTC: SFU and OpenID authorization. Secrets never enter the Nix store. + matrix-livekit = { + service.image = "livekit/livekit-server:v1.13.11"; + service.container_name = "matrix-livekit"; + out.service.mem_limit = "1g"; + service.restart = "unless-stopped"; + service.user = "65532:65532"; + service.capabilities.ALL = false; + out.service.security_opt = [ "no-new-privileges:true" ]; + out.service.read_only = true; + out.service.pids_limit = 256; + service.networks = [ "matrix-rtc" ]; + service.command = "--config /run/secrets/livekit.yaml"; + service.volumes = [ + "/var/lib/matrix-rtc-secrets/livekit.yaml:/run/secrets/livekit.yaml:ro" + "/var/lib/matrix-rtc-secrets/turn-secret:/run/secrets/turn-secret:ro" + ]; + service.ports = [ "127.0.0.1:7880:7880" "7881:7881/tcp" "7882:7882/udp" ]; + }; + matrix-rtc-jwt = { + service.image = "ghcr.io/element-hq/lk-jwt-service:0.9.0"; + service.container_name = "matrix-rtc-jwt"; + # Avoid public-IP hairpin NAT for same-host OpenID and SFU calls; TLS stays verified. + out.service.extra_hosts = [ "iscg.dev:host-gateway" ]; + out.service.mem_limit = "256m"; + service.restart = "unless-stopped"; + service.user = "65532:65532"; + service.capabilities.ALL = false; + out.service.security_opt = [ "no-new-privileges:true" ]; + out.service.read_only = true; + out.service.pids_limit = 256; + service.networks = [ "matrix-rtc" ]; + service.ports = [ "127.0.0.1:8081:8080" ]; + service.volumes = [ + "/var/lib/matrix-rtc-secrets/api-key:/run/secrets/api-key:ro" + "/var/lib/matrix-rtc-secrets/api-secret:/run/secrets/api-secret:ro" + ]; + service.environment = { + LIVEKIT_URL = "wss://iscg.dev/livekit/sfu"; + LIVEKIT_KEY_FROM_FILE = "/run/secrets/api-key"; + LIVEKIT_SECRET_FROM_FILE = "/run/secrets/api-secret"; + LIVEKIT_FULL_ACCESS_HOMESERVERS = "iscg.dev"; + LIVEKIT_JWT_BIND = ":8080"; + }; + }; cinny = { service.image = "ajbura/cinny:latest"; service.container_name = "cinny"; diff --git a/hosts/heather/default.nix b/hosts/heather/default.nix index 8f22bf6..9ce63a3 100644 --- a/hosts/heather/default.nix +++ b/hosts/heather/default.nix @@ -96,11 +96,13 @@ 22000 # syncthing sync 22067 # strelaysrv (relay) 22070 # strelaysrv (status) + 7881 # MatrixRTC LiveKit ICE/TCP 3478 # coturn TURN (tcp+udp) ]; firewall.allowedUDPPorts = [ 22000 # syncthing sync (QUIC) 10000 # jitsi jvb (RTP media) + 7882 # MatrixRTC LiveKit ICE/UDP mux 3478 # coturn TURN ]; # coturn RTP relay range