at 25.11-pre 25 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8with lib; 9 10let 11 cfg = config.services.jitsi-meet; 12 13 # The configuration files are JS of format "var <<string>> = <<JSON>>;". In order to 14 # override only some settings, we need to extract the JSON, use jq to merge it with 15 # the config provided by user, and then reconstruct the file. 16 overrideJs = 17 source: varName: userCfg: appendExtra: 18 let 19 extractor = pkgs.writeText "extractor.js" '' 20 var fs = require("fs"); 21 eval(fs.readFileSync(process.argv[2], 'utf8')); 22 process.stdout.write(JSON.stringify(eval(process.argv[3]))); 23 ''; 24 userJson = pkgs.writeText "user.json" (builtins.toJSON userCfg); 25 in 26 (pkgs.runCommand "${varName}.js" { } '' 27 ${pkgs.nodejs}/bin/node ${extractor} ${source} ${varName} > default.json 28 ( 29 echo "var ${varName} = " 30 ${pkgs.jq}/bin/jq -s '.[0] * .[1]' default.json ${userJson} 31 echo ";" 32 echo ${escapeShellArg appendExtra} 33 ) > $out 34 ''); 35 36 # Essential config - it's probably not good to have these as option default because 37 # types.attrs doesn't do merging. Let's merge explicitly, can still be overridden if 38 # user desires. 39 defaultCfg = { 40 hosts = { 41 domain = cfg.hostName; 42 muc = "conference.${cfg.hostName}"; 43 focus = "focus.${cfg.hostName}"; 44 jigasi = "jigasi.${cfg.hostName}"; 45 }; 46 bosh = "//${cfg.hostName}/http-bind"; 47 websocket = "wss://${cfg.hostName}/xmpp-websocket"; 48 49 fileRecordingsEnabled = true; 50 liveStreamingEnabled = true; 51 hiddenDomain = "recorder.${cfg.hostName}"; 52 }; 53in 54{ 55 options.services.jitsi-meet = with types; { 56 enable = mkEnableOption "Jitsi Meet - Secure, Simple and Scalable Video Conferences"; 57 58 hostName = mkOption { 59 type = str; 60 example = "meet.example.org"; 61 description = '' 62 FQDN of the Jitsi Meet instance. 63 ''; 64 }; 65 66 config = mkOption { 67 type = attrs; 68 default = { }; 69 example = literalExpression '' 70 { 71 enableWelcomePage = false; 72 defaultLang = "fi"; 73 } 74 ''; 75 description = '' 76 Client-side web application settings that override the defaults in {file}`config.js`. 77 78 See <https://github.com/jitsi/jitsi-meet/blob/master/config.js> for default 79 configuration with comments. 80 ''; 81 }; 82 83 extraConfig = mkOption { 84 type = lines; 85 default = ""; 86 description = '' 87 Text to append to {file}`config.js` web application config file. 88 89 Can be used to insert JavaScript logic to determine user's region in cascading bridges setup. 90 ''; 91 }; 92 93 interfaceConfig = mkOption { 94 type = attrs; 95 default = { }; 96 example = literalExpression '' 97 { 98 SHOW_JITSI_WATERMARK = false; 99 SHOW_WATERMARK_FOR_GUESTS = false; 100 } 101 ''; 102 description = '' 103 Client-side web-app interface settings that override the defaults in {file}`interface_config.js`. 104 105 See <https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js> for 106 default configuration with comments. 107 ''; 108 }; 109 110 videobridge = { 111 enable = mkOption { 112 type = bool; 113 default = true; 114 description = '' 115 Jitsi Videobridge instance and configure it to connect to Prosody. 116 117 Additional configuration is possible with {option}`services.jitsi-videobridge` 118 ''; 119 }; 120 121 passwordFile = mkOption { 122 type = nullOr str; 123 default = null; 124 example = "/run/keys/videobridge"; 125 description = '' 126 File containing password to the Prosody account for videobridge. 127 128 If `null`, a file with password will be generated automatically. Setting 129 this option is useful if you plan to connect additional videobridges to the XMPP server. 130 ''; 131 }; 132 }; 133 134 jicofo.enable = mkOption { 135 type = bool; 136 default = true; 137 description = '' 138 Whether to enable JiCoFo instance and configure it to connect to Prosody. 139 140 Additional configuration is possible with {option}`services.jicofo`. 141 ''; 142 }; 143 144 jibri.enable = mkOption { 145 type = bool; 146 default = false; 147 description = '' 148 Whether to enable a Jibri instance and configure it to connect to Prosody. 149 150 Additional configuration is possible with {option}`services.jibri`, and 151 {option}`services.jibri.finalizeScript` is especially useful. 152 ''; 153 }; 154 155 jigasi.enable = mkOption { 156 type = bool; 157 default = false; 158 description = '' 159 Whether to enable jigasi instance and configure it to connect to Prosody. 160 161 Additional configuration is possible with <option>services.jigasi</option>. 162 ''; 163 }; 164 165 nginx.enable = mkOption { 166 type = bool; 167 default = true; 168 description = '' 169 Whether to enable nginx virtual host that will serve the javascript application and act as 170 a proxy for the XMPP server. Further nginx configuration can be done by adapting 171 {option}`services.nginx.virtualHosts.<hostName>`. 172 When this is enabled, ACME will be used to retrieve a TLS certificate by default. To disable 173 this, set the {option}`services.nginx.virtualHosts.<hostName>.enableACME` to 174 `false` and if appropriate do the same for 175 {option}`services.nginx.virtualHosts.<hostName>.forceSSL`. 176 ''; 177 }; 178 179 caddy.enable = mkEnableOption "caddy reverse proxy to expose jitsi-meet"; 180 181 prosody.enable = mkOption { 182 type = bool; 183 default = true; 184 example = false; 185 description = '' 186 Whether to configure Prosody to relay XMPP messages between Jitsi Meet components. Turn this 187 off if you want to configure it manually. 188 ''; 189 }; 190 191 prosody.allowners_muc = mkOption { 192 type = bool; 193 default = false; 194 description = '' 195 Add module allowners, any user in chat is able to 196 kick other. Usefull in jitsi-meet to kick ghosts. 197 ''; 198 }; 199 200 prosody.lockdown = mkOption { 201 type = bool; 202 default = false; 203 example = true; 204 description = '' 205 Whether to disable Prosody features not needed by Jitsi Meet. 206 207 The default Prosody configuration assumes that it will be used as a 208 general-purpose XMPP server rather than as a companion service for 209 Jitsi Meet. This option reconfigures Prosody to only listen on 210 localhost without support for TLS termination, XMPP federation or 211 the file transfer proxy. 212 ''; 213 }; 214 215 excalidraw.enable = mkEnableOption "Excalidraw collaboration backend for Jitsi"; 216 excalidraw.port = mkOption { 217 type = types.port; 218 default = 3002; 219 description = ''The port which the Excalidraw backend for Jitsi should listen to.''; 220 }; 221 222 secureDomain = { 223 enable = mkEnableOption "Authenticated room creation"; 224 authentication = mkOption { 225 type = types.str; 226 default = "internal_hashed"; 227 description = ''The authentication type to be used by jitsi''; 228 }; 229 }; 230 }; 231 232 config = mkIf cfg.enable { 233 services.prosody = mkIf cfg.prosody.enable { 234 enable = mkDefault true; 235 xmppComplianceSuite = mkDefault false; 236 modules = { 237 admin_adhoc = mkDefault false; 238 bosh = mkDefault true; 239 ping = mkDefault true; 240 roster = mkDefault true; 241 saslauth = mkDefault true; 242 smacks = mkDefault true; 243 tls = mkDefault true; 244 websocket = mkDefault true; 245 proxy65 = mkIf cfg.prosody.lockdown (mkDefault false); 246 }; 247 httpInterfaces = mkIf cfg.prosody.lockdown (mkDefault [ "127.0.0.1" ]); 248 httpsPorts = mkIf cfg.prosody.lockdown (mkDefault [ ]); 249 muc = [ 250 { 251 domain = "conference.${cfg.hostName}"; 252 name = "Jitsi Meet MUC"; 253 allowners_muc = cfg.prosody.allowners_muc; 254 roomLocking = false; 255 roomDefaultPublicJids = true; 256 extraConfig = '' 257 restrict_room_creation = true 258 storage = "memory" 259 admins = { "focus@auth.${cfg.hostName}" } 260 ''; 261 } 262 { 263 domain = "breakout.${cfg.hostName}"; 264 name = "Jitsi Meet Breakout MUC"; 265 roomLocking = false; 266 roomDefaultPublicJids = true; 267 extraConfig = '' 268 restrict_room_creation = true 269 storage = "memory" 270 admins = { "focus@auth.${cfg.hostName}", "jvb@auth.${cfg.hostName}" } 271 ''; 272 } 273 { 274 domain = "internal.auth.${cfg.hostName}"; 275 name = "Jitsi Meet Videobridge MUC"; 276 roomLocking = false; 277 roomDefaultPublicJids = true; 278 extraConfig = '' 279 storage = "memory" 280 admins = { "focus@auth.${cfg.hostName}", "jvb@auth.${cfg.hostName}", "jigasi@auth.${cfg.hostName}" } 281 ''; 282 #-- muc_room_cache_size = 1000 283 } 284 { 285 domain = "lobby.${cfg.hostName}"; 286 name = "Jitsi Meet Lobby MUC"; 287 roomLocking = false; 288 roomDefaultPublicJids = true; 289 extraConfig = '' 290 restrict_room_creation = true 291 storage = "memory" 292 ''; 293 } 294 ]; 295 extraModules = [ 296 "pubsub" 297 "smacks" 298 "speakerstats" 299 "external_services" 300 "conference_duration" 301 "end_conference" 302 "muc_lobby_rooms" 303 "muc_breakout_rooms" 304 "av_moderation" 305 "muc_hide_all" 306 "muc_meeting_id" 307 "muc_domain_mapper" 308 "muc_rate_limit" 309 "limits_exception" 310 "persistent_lobby" 311 "room_metadata" 312 ]; 313 extraPluginPaths = [ "${pkgs.jitsi-meet-prosody}/share/prosody-plugins" ]; 314 extraConfig = lib.mkMerge [ 315 (mkAfter '' 316 Component "focus.${cfg.hostName}" "client_proxy" 317 target_address = "focus@auth.${cfg.hostName}" 318 319 Component "jigasi.${cfg.hostName}" "client_proxy" 320 target_address = "jigasi@auth.${cfg.hostName}" 321 322 Component "speakerstats.${cfg.hostName}" "speakerstats_component" 323 muc_component = "conference.${cfg.hostName}" 324 325 Component "conferenceduration.${cfg.hostName}" "conference_duration_component" 326 muc_component = "conference.${cfg.hostName}" 327 328 Component "endconference.${cfg.hostName}" "end_conference" 329 muc_component = "conference.${cfg.hostName}" 330 331 Component "avmoderation.${cfg.hostName}" "av_moderation_component" 332 muc_component = "conference.${cfg.hostName}" 333 334 Component "metadata.${cfg.hostName}" "room_metadata_component" 335 muc_component = "conference.${cfg.hostName}" 336 breakout_rooms_component = "breakout.${cfg.hostName}" 337 '') 338 (mkBefore ( 339 '' 340 muc_mapper_domain_base = "${cfg.hostName}" 341 342 cross_domain_websocket = true; 343 consider_websocket_secure = true; 344 345 unlimited_jids = { 346 "focus@auth.${cfg.hostName}", 347 "jvb@auth.${cfg.hostName}" 348 } 349 '' 350 + optionalString cfg.prosody.lockdown '' 351 c2s_interfaces = { "127.0.0.1" }; 352 modules_disabled = { "s2s" }; 353 '' 354 )) 355 ]; 356 virtualHosts.${cfg.hostName} = { 357 enabled = true; 358 domain = cfg.hostName; 359 extraConfig = '' 360 authentication = ${ 361 if cfg.secureDomain.enable then "\"${cfg.secureDomain.authentication}\"" else "\"jitsi-anonymous\"" 362 } 363 c2s_require_encryption = false 364 admins = { "focus@auth.${cfg.hostName}" } 365 smacks_max_unacked_stanzas = 5 366 smacks_hibernation_time = 60 367 smacks_max_hibernated_sessions = 1 368 smacks_max_old_sessions = 1 369 370 av_moderation_component = "avmoderation.${cfg.hostName}" 371 speakerstats_component = "speakerstats.${cfg.hostName}" 372 conference_duration_component = "conferenceduration.${cfg.hostName}" 373 end_conference_component = "endconference.${cfg.hostName}" 374 375 c2s_require_encryption = false 376 lobby_muc = "lobby.${cfg.hostName}" 377 breakout_rooms_muc = "breakout.${cfg.hostName}" 378 room_metadata_component = "metadata.${cfg.hostName}" 379 main_muc = "conference.${cfg.hostName}" 380 ''; 381 ssl = { 382 cert = "/var/lib/jitsi-meet/jitsi-meet.crt"; 383 key = "/var/lib/jitsi-meet/jitsi-meet.key"; 384 }; 385 }; 386 virtualHosts."auth.${cfg.hostName}" = { 387 enabled = true; 388 domain = "auth.${cfg.hostName}"; 389 extraConfig = '' 390 authentication = "internal_hashed" 391 ''; 392 ssl = { 393 cert = "/var/lib/jitsi-meet/jitsi-meet.crt"; 394 key = "/var/lib/jitsi-meet/jitsi-meet.key"; 395 }; 396 }; 397 virtualHosts."recorder.${cfg.hostName}" = { 398 enabled = true; 399 domain = "recorder.${cfg.hostName}"; 400 extraConfig = '' 401 authentication = "internal_plain" 402 c2s_require_encryption = false 403 ''; 404 }; 405 virtualHosts."guest.${cfg.hostName}" = { 406 enabled = true; 407 domain = "guest.${cfg.hostName}"; 408 extraConfig = '' 409 authentication = "anonymous" 410 c2s_require_encryption = false 411 ''; 412 }; 413 }; 414 systemd.services.prosody = mkIf cfg.prosody.enable { 415 preStart = 416 let 417 videobridgeSecret = 418 if cfg.videobridge.passwordFile != null then 419 cfg.videobridge.passwordFile 420 else 421 "/var/lib/jitsi-meet/videobridge-secret"; 422 in 423 '' 424 ${config.services.prosody.package}/bin/prosodyctl register focus auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jicofo-user-secret)" 425 ${config.services.prosody.package}/bin/prosodyctl register jvb auth.${cfg.hostName} "$(cat ${videobridgeSecret})" 426 ${config.services.prosody.package}/bin/prosodyctl mod_roster_command subscribe focus.${cfg.hostName} focus@auth.${cfg.hostName} 427 ${config.services.prosody.package}/bin/prosodyctl register jibri auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jibri-auth-secret)" 428 ${config.services.prosody.package}/bin/prosodyctl register recorder recorder.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jibri-recorder-secret)" 429 '' 430 + optionalString cfg.jigasi.enable '' 431 ${config.services.prosody.package}/bin/prosodyctl register jigasi auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jigasi-user-secret)" 432 ''; 433 434 serviceConfig = { 435 EnvironmentFile = [ "/var/lib/jitsi-meet/secrets-env" ]; 436 SupplementaryGroups = [ "jitsi-meet" ]; 437 }; 438 reloadIfChanged = true; 439 }; 440 441 users.groups.jitsi-meet = { }; 442 systemd.tmpfiles.rules = [ 443 "d '/var/lib/jitsi-meet' 0750 root jitsi-meet - -" 444 ]; 445 446 systemd.services.jitsi-meet-init-secrets = { 447 wantedBy = [ "multi-user.target" ]; 448 before = 449 [ 450 "jicofo.service" 451 "jitsi-videobridge2.service" 452 ] 453 ++ (optional cfg.prosody.enable "prosody.service") 454 ++ (optional cfg.jigasi.enable "jigasi.service"); 455 serviceConfig = { 456 Type = "oneshot"; 457 UMask = "027"; 458 User = "root"; 459 Group = "jitsi-meet"; 460 WorkingDirectory = "/var/lib/jitsi-meet"; 461 }; 462 463 script = 464 let 465 secrets = 466 [ 467 "jicofo-component-secret" 468 "jicofo-user-secret" 469 "jibri-auth-secret" 470 "jibri-recorder-secret" 471 ] 472 ++ (optionals cfg.jigasi.enable [ 473 "jigasi-user-secret" 474 "jigasi-component-secret" 475 ]) 476 ++ (optional (cfg.videobridge.passwordFile == null) "videobridge-secret"); 477 in 478 '' 479 ${concatMapStringsSep "\n" (s: '' 480 if [ ! -f ${s} ]; then 481 tr -dc a-zA-Z0-9 </dev/urandom | head -c 64 > ${s} 482 fi 483 '') secrets} 484 485 # for easy access in prosody 486 echo "JICOFO_COMPONENT_SECRET=$(cat jicofo-component-secret)" > secrets-env 487 echo "JIGASI_COMPONENT_SECRET=$(cat jigasi-component-secret)" >> secrets-env 488 '' 489 + optionalString cfg.prosody.enable '' 490 # generate self-signed certificates 491 if [ ! -f /var/lib/jitsi-meet/jitsi-meet.crt ]; then 492 ${getBin pkgs.openssl}/bin/openssl req \ 493 -x509 \ 494 -newkey rsa:4096 \ 495 -keyout /var/lib/jitsi-meet/jitsi-meet.key \ 496 -out /var/lib/jitsi-meet/jitsi-meet.crt \ 497 -days 36500 \ 498 -nodes \ 499 -subj '/CN=${cfg.hostName}/CN=auth.${cfg.hostName}' 500 chmod 640 /var/lib/jitsi-meet/jitsi-meet.key 501 fi 502 ''; 503 }; 504 505 systemd.services.jitsi-excalidraw = mkIf cfg.excalidraw.enable { 506 description = "Excalidraw collaboration backend for Jitsi"; 507 after = [ "network.target" ]; 508 wantedBy = [ "multi-user.target" ]; 509 environment.PORT = toString cfg.excalidraw.port; 510 511 serviceConfig = { 512 Type = "simple"; 513 ExecStart = "${pkgs.jitsi-excalidraw}/bin/jitsi-excalidraw-backend"; 514 Restart = "on-failure"; 515 516 DynamicUser = true; 517 Group = "jitsi-meet"; 518 CapabilityBoundingSet = ""; 519 NoNewPrivileges = true; 520 ProtectSystem = "strict"; 521 ProtectClock = true; 522 ProtectHome = true; 523 ProtectProc = true; 524 ProtectKernelLogs = true; 525 PrivateTmp = true; 526 PrivateDevices = true; 527 PrivateUsers = true; 528 ProtectHostname = true; 529 ProtectKernelTunables = true; 530 ProtectKernelModules = true; 531 ProtectControlGroups = true; 532 RestrictAddressFamilies = [ 533 "AF_INET" 534 "AF_INET6" 535 ]; 536 RestrictNamespaces = true; 537 LockPersonality = true; 538 RestrictRealtime = true; 539 RestrictSUIDSGID = true; 540 SystemCallFilter = [ 541 "@system-service @pkey" 542 "~@privileged" 543 ]; 544 }; 545 }; 546 547 services.nginx = mkIf cfg.nginx.enable { 548 enable = mkDefault true; 549 virtualHosts.${cfg.hostName} = { 550 enableACME = mkDefault true; 551 forceSSL = mkDefault true; 552 root = pkgs.jitsi-meet; 553 extraConfig = '' 554 ssi on; 555 ''; 556 locations."@root_path".extraConfig = '' 557 rewrite ^/(.*)$ / break; 558 ''; 559 locations."~ ^/([^/\\?&:'\"]+)$".tryFiles = "$uri @root_path"; 560 locations."^~ /xmpp-websocket" = { 561 priority = 100; 562 proxyPass = "http://localhost:5280/xmpp-websocket"; 563 proxyWebsockets = true; 564 }; 565 locations."=/http-bind" = { 566 proxyPass = "http://localhost:5280/http-bind"; 567 extraConfig = '' 568 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 569 proxy_set_header Host $host; 570 ''; 571 }; 572 locations."=/external_api.js" = mkDefault { 573 alias = "${pkgs.jitsi-meet}/libs/external_api.min.js"; 574 }; 575 locations."=/_api/room-info" = { 576 proxyPass = "http://localhost:5280/room-info"; 577 extraConfig = '' 578 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 579 proxy_set_header Host $host; 580 ''; 581 }; 582 locations."=/config.js" = mkDefault { 583 alias = 584 overrideJs "${pkgs.jitsi-meet}/config.js" "config" (recursiveUpdate defaultCfg cfg.config) 585 cfg.extraConfig; 586 }; 587 locations."=/interface_config.js" = mkDefault { 588 alias = 589 overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig 590 ""; 591 }; 592 locations."/socket.io/" = mkIf cfg.excalidraw.enable { 593 proxyPass = "http://127.0.0.1:${toString cfg.excalidraw.port}"; 594 proxyWebsockets = true; 595 }; 596 }; 597 }; 598 599 services.caddy = mkIf cfg.caddy.enable { 600 enable = mkDefault true; 601 virtualHosts.${cfg.hostName} = { 602 extraConfig = 603 let 604 templatedJitsiMeet = pkgs.runCommand "templated-jitsi-meet" { } '' 605 cp -R --no-preserve=all ${pkgs.jitsi-meet}/* . 606 for file in *.html **/*.html ; do 607 ${pkgs.sd}/bin/sd '<!--#include virtual="(.*)" -->' '{{ include "$1" }}' $file 608 done 609 rm config.js 610 rm interface_config.js 611 cp -R . $out 612 cp ${ 613 overrideJs "${pkgs.jitsi-meet}/config.js" "config" (recursiveUpdate defaultCfg cfg.config) 614 cfg.extraConfig 615 } $out/config.js 616 cp ${ 617 overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig "" 618 } $out/interface_config.js 619 cp ./libs/external_api.min.js $out/external_api.js 620 ''; 621 in 622 (optionalString cfg.excalidraw.enable '' 623 handle /socket.io/ { 624 reverse_proxy 127.0.0.1:${toString cfg.excalidraw.port} 625 } 626 '') 627 + '' 628 handle /http-bind { 629 header Host ${cfg.hostName} 630 reverse_proxy 127.0.0.1:5280 631 } 632 handle /xmpp-websocket { 633 reverse_proxy 127.0.0.1:5280 634 } 635 handle { 636 templates 637 root * ${templatedJitsiMeet} 638 try_files {path} {path} 639 try_files {path} /index.html 640 file_server 641 } 642 ''; 643 }; 644 }; 645 646 services.jitsi-meet.config = 647 recursiveUpdate 648 (mkIf cfg.excalidraw.enable { 649 whiteboard = { 650 enabled = true; 651 collabServerBaseUrl = "https://${cfg.hostName}"; 652 }; 653 }) 654 ( 655 mkIf cfg.secureDomain.enable { 656 hosts.anonymousdomain = "guest.${cfg.hostName}"; 657 } 658 ); 659 660 services.jitsi-videobridge = mkIf cfg.videobridge.enable { 661 enable = true; 662 xmppConfigs."localhost" = { 663 userName = "jvb"; 664 domain = "auth.${cfg.hostName}"; 665 passwordFile = "/var/lib/jitsi-meet/videobridge-secret"; 666 mucJids = "jvbbrewery@internal.auth.${cfg.hostName}"; 667 disableCertificateVerification = true; 668 }; 669 }; 670 671 services.jicofo = mkIf cfg.jicofo.enable { 672 enable = true; 673 xmppHost = "localhost"; 674 xmppDomain = cfg.hostName; 675 userDomain = "auth.${cfg.hostName}"; 676 userName = "focus"; 677 userPasswordFile = "/var/lib/jitsi-meet/jicofo-user-secret"; 678 componentPasswordFile = "/var/lib/jitsi-meet/jicofo-component-secret"; 679 bridgeMuc = "jvbbrewery@internal.auth.${cfg.hostName}"; 680 config = mkMerge [ 681 { 682 jicofo.xmpp.service.disable-certificate-verification = true; 683 jicofo.xmpp.client.disable-certificate-verification = true; 684 } 685 (lib.mkIf (config.services.jibri.enable || cfg.jibri.enable) { 686 jicofo.jibri = { 687 brewery-jid = "JibriBrewery@internal.auth.${cfg.hostName}"; 688 pending-timeout = "90"; 689 }; 690 }) 691 (lib.mkIf cfg.secureDomain.enable { 692 jicofo = { 693 authentication = { 694 enabled = "true"; 695 type = "XMPP"; 696 login-url = cfg.hostName; 697 }; 698 xmpp.client.client-proxy = "focus.${cfg.hostName}"; 699 }; 700 }) 701 ]; 702 }; 703 704 services.jibri = mkIf cfg.jibri.enable { 705 enable = true; 706 707 xmppEnvironments."jitsi-meet" = { 708 xmppServerHosts = [ "localhost" ]; 709 xmppDomain = cfg.hostName; 710 711 control.muc = { 712 domain = "internal.auth.${cfg.hostName}"; 713 roomName = "JibriBrewery"; 714 nickname = "jibri"; 715 }; 716 717 control.login = { 718 domain = "auth.${cfg.hostName}"; 719 username = "jibri"; 720 passwordFile = "/var/lib/jitsi-meet/jibri-auth-secret"; 721 }; 722 723 call.login = { 724 domain = "recorder.${cfg.hostName}"; 725 username = "recorder"; 726 passwordFile = "/var/lib/jitsi-meet/jibri-recorder-secret"; 727 }; 728 729 usageTimeout = "0"; 730 disableCertificateVerification = true; 731 stripFromRoomDomain = "conference."; 732 }; 733 }; 734 735 services.jigasi = mkIf cfg.jigasi.enable { 736 enable = true; 737 xmppHost = "localhost"; 738 xmppDomain = cfg.hostName; 739 userDomain = "auth.${cfg.hostName}"; 740 userName = "jigasi"; 741 userPasswordFile = "/var/lib/jitsi-meet/jigasi-user-secret"; 742 componentPasswordFile = "/var/lib/jitsi-meet/jigasi-component-secret"; 743 bridgeMuc = "jigasibrewery@internal.${cfg.hostName}"; 744 config = { 745 "org.jitsi.jigasi.ALWAYS_TRUST_MODE_ENABLED" = "true"; 746 }; 747 }; 748 }; 749 750 meta.doc = ./jitsi-meet.md; 751 meta.maintainers = lib.teams.jitsi.members; 752}