lol

Merge pull request #227588 from camillemndn/jitsi-meet

nixos/jitsi-meet: updated prosody, support secure domain setup and Excalidraw whiteboards

authored by

Julien Malka and committed by
GitHub
cac11727 19e27c35

+201 -19
+159 -19
nixos/modules/services/web-apps/jitsi-meet.nix
··· 169 169 off if you want to configure it manually. 170 170 ''; 171 171 }; 172 + 173 + excalidraw.enable = mkEnableOption (lib.mdDoc "Excalidraw collaboration backend for Jitsi"); 174 + excalidraw.port = mkOption { 175 + type = types.port; 176 + default = 3002; 177 + description = lib.mdDoc ''The port which the Excalidraw backend for Jitsi should listen to.''; 178 + }; 179 + 180 + secureDomain.enable = mkEnableOption (lib.mdDoc "Authenticated room creation"); 172 181 }; 173 182 174 183 config = mkIf cfg.enable { ··· 192 201 roomLocking = false; 193 202 roomDefaultPublicJids = true; 194 203 extraConfig = '' 204 + restrict_room_creation = true 195 205 storage = "memory" 206 + admins = { "focus@auth.${cfg.hostName}" } 196 207 ''; 197 208 } 198 209 { 199 - domain = "internal.${cfg.hostName}"; 210 + domain = "breakout.${cfg.hostName}"; 211 + name = "Jitsi Meet Breakout MUC"; 212 + roomLocking = false; 213 + roomDefaultPublicJids = true; 214 + extraConfig = '' 215 + restrict_room_creation = true 216 + storage = "memory" 217 + admins = { "focus@auth.${cfg.hostName}" } 218 + ''; 219 + } 220 + { 221 + domain = "internal.auth.${cfg.hostName}"; 200 222 name = "Jitsi Meet Videobridge MUC"; 223 + roomLocking = false; 224 + roomDefaultPublicJids = true; 201 225 extraConfig = '' 202 226 storage = "memory" 203 227 admins = { "focus@auth.${cfg.hostName}", "jvb@auth.${cfg.hostName}" } 204 228 ''; 205 229 #-- muc_room_cache_size = 1000 206 230 } 231 + { 232 + domain = "lobby.${cfg.hostName}"; 233 + name = "Jitsi Meet Lobby MUC"; 234 + roomLocking = false; 235 + roomDefaultPublicJids = true; 236 + extraConfig = '' 237 + restrict_room_creation = true 238 + storage = "memory" 239 + ''; 240 + } 207 241 ]; 208 - extraModules = [ "pubsub" "smacks" ]; 242 + extraModules = [ 243 + "pubsub" 244 + "smacks" 245 + "speakerstats" 246 + "external_services" 247 + "conference_duration" 248 + "end_conference" 249 + "muc_lobby_rooms" 250 + "muc_breakout_rooms" 251 + "av_moderation" 252 + "muc_hide_all" 253 + "muc_meeting_id" 254 + "muc_domain_mapper" 255 + "muc_rate_limit" 256 + "limits_exception" 257 + "persistent_lobby" 258 + "room_metadata" 259 + ]; 209 260 extraPluginPaths = [ "${pkgs.jitsi-meet-prosody}/share/prosody-plugins" ]; 210 - extraConfig = lib.mkMerge [ (mkAfter '' 211 - Component "focus.${cfg.hostName}" "client_proxy" 212 - target_address = "focus@auth.${cfg.hostName}" 261 + extraConfig = lib.mkMerge [ 262 + (mkAfter '' 263 + Component "focus.${cfg.hostName}" "client_proxy" 264 + target_address = "focus@auth.${cfg.hostName}" 265 + 266 + Component "speakerstats.${cfg.hostName}" "speakerstats_component" 267 + muc_component = "conference.${cfg.hostName}" 268 + 269 + Component "conferenceduration.${cfg.hostName}" "conference_duration_component" 270 + muc_component = "conference.${cfg.hostName}" 271 + 272 + Component "endconference.${cfg.hostName}" "end_conference" 273 + muc_component = "conference.${cfg.hostName}" 274 + 275 + Component "avmoderation.${cfg.hostName}" "av_moderation_component" 276 + muc_component = "conference.${cfg.hostName}" 277 + 278 + Component "metadata.${cfg.hostName}" "room_metadata_component" 279 + muc_component = "conference.${cfg.hostName}" 280 + breakout_rooms_component = "breakout.${cfg.hostName}" 213 281 '') 214 282 (mkBefore '' 283 + muc_mapper_domain_base = "${cfg.hostName}" 284 + 215 285 cross_domain_websocket = true; 216 286 consider_websocket_secure = true; 287 + 288 + unlimited_jids = { 289 + "focus@auth.${cfg.hostName}", 290 + "jvb@auth.${cfg.hostName}" 291 + } 217 292 '') 218 293 ]; 219 294 virtualHosts.${cfg.hostName} = { 220 295 enabled = true; 221 296 domain = cfg.hostName; 222 297 extraConfig = '' 223 - authentication = "anonymous" 298 + authentication = ${if cfg.secureDomain.enable then "\"internal_hashed\"" else "\"jitsi-anonymous\""} 224 299 c2s_require_encryption = false 225 300 admins = { "focus@auth.${cfg.hostName}" } 226 301 smacks_max_unacked_stanzas = 5 227 302 smacks_hibernation_time = 60 228 303 smacks_max_hibernated_sessions = 1 229 304 smacks_max_old_sessions = 1 305 + 306 + av_moderation_component = "avmoderation.${cfg.hostName}" 307 + speakerstats_component = "speakerstats.${cfg.hostName}" 308 + conference_duration_component = "conferenceduration.${cfg.hostName}" 309 + end_conference_component = "endconference.${cfg.hostName}" 310 + 311 + c2s_require_encryption = false 312 + lobby_muc = "lobby.${cfg.hostName}" 313 + breakout_rooms_muc = "breakout.${cfg.hostName}" 314 + room_metadata_component = "metadata.${cfg.hostName}" 315 + main_muc = "conference.${cfg.hostName}" 230 316 ''; 231 317 ssl = { 232 318 cert = "/var/lib/jitsi-meet/jitsi-meet.crt"; ··· 237 323 enabled = true; 238 324 domain = "auth.${cfg.hostName}"; 239 325 extraConfig = '' 240 - authentication = "internal_plain" 326 + authentication = "internal_hashed" 241 327 ''; 242 328 ssl = { 243 329 cert = "/var/lib/jitsi-meet/jitsi-meet.crt"; ··· 252 338 c2s_require_encryption = false 253 339 ''; 254 340 }; 341 + virtualHosts."guest.${cfg.hostName}" = { 342 + enabled = true; 343 + domain = "guest.${cfg.hostName}"; 344 + extraConfig = '' 345 + authentication = "anonymous" 346 + c2s_require_encryption = false 347 + ''; 348 + }; 255 349 }; 256 350 systemd.services.prosody = mkIf cfg.prosody.enable { 257 351 preStart = let ··· 270 364 reloadIfChanged = true; 271 365 }; 272 366 273 - users.groups.jitsi-meet = {}; 367 + users.groups.jitsi-meet = { }; 274 368 systemd.tmpfiles.rules = [ 275 369 "d '/var/lib/jitsi-meet' 0750 root jitsi-meet - -" 276 370 ]; ··· 317 411 ''; 318 412 }; 319 413 414 + systemd.services.jitsi-excalidraw = mkIf cfg.excalidraw.enable { 415 + description = "Excalidraw collaboration backend for Jitsi"; 416 + after = [ "network.target" ]; 417 + wantedBy = [ "multi-user.target" ]; 418 + environment.PORT = toString cfg.excalidraw.port; 419 + 420 + serviceConfig = { 421 + Type = "simple"; 422 + ExecStart = "${pkgs.jitsi-excalidraw}/bin/jitsi-excalidraw-backend"; 423 + Restart = "on-failure"; 424 + Group = "jitsi-meet"; 425 + }; 426 + }; 427 + 320 428 services.nginx = mkIf cfg.nginx.enable { 321 429 enable = mkDefault true; 322 430 virtualHosts.${cfg.hostName} = { ··· 345 453 locations."=/external_api.js" = mkDefault { 346 454 alias = "${pkgs.jitsi-meet}/libs/external_api.min.js"; 347 455 }; 456 + locations."=/_api/room-info" = { 457 + proxyPass = "http://localhost:5280/room-info"; 458 + extraConfig = '' 459 + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 460 + proxy_set_header Host $host; 461 + ''; 462 + }; 348 463 locations."=/config.js" = mkDefault { 349 464 alias = overrideJs "${pkgs.jitsi-meet}/config.js" "config" (recursiveUpdate defaultCfg cfg.config) cfg.extraConfig; 350 465 }; 351 466 locations."=/interface_config.js" = mkDefault { 352 467 alias = overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig ""; 353 468 }; 469 + locations."/socket.io/" = mkIf cfg.excalidraw.enable { 470 + proxyPass = "http://127.0.0.1:${toString cfg.excalidraw.port}"; 471 + proxyWebsockets = true; 472 + }; 354 473 }; 355 474 }; 356 475 ··· 359 478 virtualHosts.${cfg.hostName} = { 360 479 extraConfig = 361 480 let 362 - templatedJitsiMeet = pkgs.runCommand "templated-jitsi-meet" {} '' 481 + templatedJitsiMeet = pkgs.runCommand "templated-jitsi-meet" { } '' 363 482 cp -R ${pkgs.jitsi-meet}/* . 364 483 for file in *.html **/*.html ; do 365 484 ${pkgs.sd}/bin/sd '<!--#include virtual="(.*)" -->' '{{ include "$1" }}' $file ··· 390 509 }; 391 510 }; 392 511 512 + services.jitsi-meet.config = recursiveUpdate 513 + (mkIf cfg.excalidraw.enable { 514 + whiteboard = { 515 + enabled = true; 516 + collabServerBaseUrl = "https://${cfg.hostName}"; 517 + }; 518 + }) 519 + (mkIf cfg.secureDomain.enable { 520 + hosts.anonymousdomain = "guest.${cfg.hostName}"; 521 + }); 522 + 393 523 services.jitsi-videobridge = mkIf cfg.videobridge.enable { 394 524 enable = true; 395 525 xmppConfigs."localhost" = { 396 526 userName = "jvb"; 397 527 domain = "auth.${cfg.hostName}"; 398 528 passwordFile = "/var/lib/jitsi-meet/videobridge-secret"; 399 - mucJids = "jvbbrewery@internal.${cfg.hostName}"; 529 + mucJids = "jvbbrewery@internal.auth.${cfg.hostName}"; 400 530 disableCertificateVerification = true; 401 531 }; 402 532 }; ··· 409 539 userName = "focus"; 410 540 userPasswordFile = "/var/lib/jitsi-meet/jicofo-user-secret"; 411 541 componentPasswordFile = "/var/lib/jitsi-meet/jicofo-component-secret"; 412 - bridgeMuc = "jvbbrewery@internal.${cfg.hostName}"; 542 + bridgeMuc = "jvbbrewery@internal.auth.${cfg.hostName}"; 413 543 config = mkMerge [{ 414 544 jicofo.xmpp.service.disable-certificate-verification = true; 415 545 jicofo.xmpp.client.disable-certificate-verification = true; 416 - #} (lib.mkIf cfg.jibri.enable { 417 - } (lib.mkIf (config.services.jibri.enable || cfg.jibri.enable) { 418 - jicofo.jibri = { 419 - brewery-jid = "JibriBrewery@internal.${cfg.hostName}"; 420 - pending-timeout = "90"; 421 - }; 422 - })]; 546 + } 547 + (lib.mkIf (config.services.jibri.enable || cfg.jibri.enable) { 548 + jicofo.jibri = { 549 + brewery-jid = "JibriBrewery@internal.auth.${cfg.hostName}"; 550 + pending-timeout = "90"; 551 + }; 552 + }) 553 + (lib.mkIf cfg.secureDomain.enable { 554 + jicofo = { 555 + authentication = { 556 + enabled = "true"; 557 + type = "XMPP"; 558 + login-url = cfg.hostName; 559 + }; 560 + xmpp.client.client-proxy = "focus.${cfg.hostName}"; 561 + }; 562 + })]; 423 563 }; 424 564 425 565 services.jibri = mkIf cfg.jibri.enable { ··· 430 570 xmppDomain = cfg.hostName; 431 571 432 572 control.muc = { 433 - domain = "internal.${cfg.hostName}"; 573 + domain = "internal.auth.${cfg.hostName}"; 434 574 roomName = "JibriBrewery"; 435 575 nickname = "jibri"; 436 576 };
+40
pkgs/servers/jitsi-excalidraw/default.nix
··· 1 + { lib 2 + , buildNpmPackage 3 + , fetchFromGitHub 4 + , nodejs 5 + , python3 6 + }: 7 + 8 + buildNpmPackage rec { 9 + pname = "jitsi-excalidraw-backend"; 10 + version = "17"; 11 + 12 + src = fetchFromGitHub { 13 + owner = "jitsi"; 14 + repo = "excalidraw-backend"; 15 + rev = "x${version}"; 16 + hash = "sha256-aQePkVA8KRL06VewiD0ePRpj88pAItcV7B2SBnRRtCs="; 17 + }; 18 + 19 + npmDepsHash = "sha256-BJqjaqTeg5i+ECGMuiBYVToK2i2XCOVP9yeDFz6nP4k="; 20 + 21 + nativeBuildInputs = [ python3 ]; 22 + 23 + installPhase = '' 24 + mkdir -p $out/share 25 + cp -r {node_modules,dist} $out/share 26 + ''; 27 + 28 + postFixup = '' 29 + makeWrapper ${nodejs}/bin/node $out/bin/jitsi-excalidraw-backend \ 30 + --add-flags dist/index.js \ 31 + --chdir $out/share 32 + ''; 33 + 34 + meta = with lib; { 35 + description = "Excalidraw collaboration backend for Jitsi"; 36 + homepage = "https://github.com/jitsi/excalidraw-backend"; 37 + license = licenses.mit; 38 + maintainers = with maintainers; [ camillemndn ]; 39 + }; 40 + }
+2
pkgs/top-level/all-packages.nix
··· 26552 26552 26553 26553 jicofo = callPackage ../servers/jicofo { }; 26554 26554 26555 + jitsi-excalidraw = callPackage ../servers/jitsi-excalidraw { }; 26556 + 26555 26557 jitsi-meet = callPackage ../servers/web-apps/jitsi-meet { }; 26556 26558 26557 26559 jitsi-meet-prosody = callPackage ../misc/jitsi-meet-prosody { };