{ config, pkgs, lib, ... }: let keyFile = "/run/livekit.key"; domain = "livekit.crans.org"; in { services.livekit' = { enable = true; openFirewall = true; settings = { port = 8100; room.auto_create = true; rtc = { use_external_ip = false; node_ip = config.crans.networking.srv.ipv4; tcp_port = 8101; port_range_start = 50000; port_range_end = 52000; enable_loopback_candidate = false; turn_servers = [ { host = config.services.coturn.realm; port = 3478; protocol = "tcp"; secretFile = config.age.secrets.coturn_auth_secret.path; } { host = config.services.coturn.realm; port = 3478; protocol = "udp"; secretFile = config.age.secrets.coturn_auth_secret.path; } { host = config.services.coturn.realm; port = 5349; protocol = "tls"; secretFile = config.age.secrets.coturn_auth_secret.path; } ]; }; turn.enabled = false; }; inherit keyFile; }; networking.firewall = let range = with config.services.livekit'.settings.rtc; lib.singleton { from = port_range_start; to = port_range_end; }; in { allowedUDPPortRanges = range; allowedUDPPorts = [ 8100 8101 8102 ]; allowedTCPPortRanges = range; allowedTCPPorts = [ 8100 8101 8102 ]; }; users.users.livekit.extraGroups = [ "turnserver" ]; services.lk-jwt-service = { enable = true; port = 8102; livekitUrl = "wss://${domain}"; inherit keyFile; }; systemd.services.livekit-key = { before = [ "lk-jwt-service.service" "livekit.service" ]; wantedBy = [ "multi-user.target" ]; path = with pkgs; [ livekit coreutils gawk ]; script = '' echo "Key missing, generating key" echo "lk-jwt-service: $(livekit-server generate-keys | tail -1 | awk '{print $3}')" > "${keyFile}" ''; serviceConfig.Type = "oneshot"; unitConfig.ConditionPathExists = "!${keyFile}"; }; systemd.services.lk-jwt-service.environment.LIVEKIT_FULL_ACCESS_HOMESERVERS = "crans.org"; services.nginx.virtualHosts."${domain}" = { enableACME = true; forceSSL = true; locations."~ /(get_token|healthz|sfu/get)" = { proxyPass = "http://localhost:${toString config.services.lk-jwt-service.port}"; }; locations."/" = { proxyPass = "http://localhost:${toString config.services.livekit'.settings.port}"; proxyWebsockets = true; }; }; age.secrets = { autofocus-config = { file = ../../../secrets/zora/services/autofocus-config.age; mode = "444"; }; }; }