Merge pull request #227588 from camillemndn/jitsi-meet

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

Changed files
+201 -19
nixos
modules
services
web-apps
pkgs
servers
jitsi-excalidraw
top-level
+159 -19
nixos/modules/services/web-apps/jitsi-meet.nix
···
off if you want to configure it manually.
'';
};
+
+
excalidraw.enable = mkEnableOption (lib.mdDoc "Excalidraw collaboration backend for Jitsi");
+
excalidraw.port = mkOption {
+
type = types.port;
+
default = 3002;
+
description = lib.mdDoc ''The port which the Excalidraw backend for Jitsi should listen to.'';
+
};
+
+
secureDomain.enable = mkEnableOption (lib.mdDoc "Authenticated room creation");
};
config = mkIf cfg.enable {
···
roomLocking = false;
roomDefaultPublicJids = true;
extraConfig = ''
+
restrict_room_creation = true
storage = "memory"
+
admins = { "focus@auth.${cfg.hostName}" }
'';
}
{
-
domain = "internal.${cfg.hostName}";
+
domain = "breakout.${cfg.hostName}";
+
name = "Jitsi Meet Breakout MUC";
+
roomLocking = false;
+
roomDefaultPublicJids = true;
+
extraConfig = ''
+
restrict_room_creation = true
+
storage = "memory"
+
admins = { "focus@auth.${cfg.hostName}" }
+
'';
+
}
+
{
+
domain = "internal.auth.${cfg.hostName}";
name = "Jitsi Meet Videobridge MUC";
+
roomLocking = false;
+
roomDefaultPublicJids = true;
extraConfig = ''
storage = "memory"
admins = { "focus@auth.${cfg.hostName}", "jvb@auth.${cfg.hostName}" }
'';
#-- muc_room_cache_size = 1000
}
+
{
+
domain = "lobby.${cfg.hostName}";
+
name = "Jitsi Meet Lobby MUC";
+
roomLocking = false;
+
roomDefaultPublicJids = true;
+
extraConfig = ''
+
restrict_room_creation = true
+
storage = "memory"
+
'';
+
}
];
-
extraModules = [ "pubsub" "smacks" ];
+
extraModules = [
+
"pubsub"
+
"smacks"
+
"speakerstats"
+
"external_services"
+
"conference_duration"
+
"end_conference"
+
"muc_lobby_rooms"
+
"muc_breakout_rooms"
+
"av_moderation"
+
"muc_hide_all"
+
"muc_meeting_id"
+
"muc_domain_mapper"
+
"muc_rate_limit"
+
"limits_exception"
+
"persistent_lobby"
+
"room_metadata"
+
];
extraPluginPaths = [ "${pkgs.jitsi-meet-prosody}/share/prosody-plugins" ];
-
extraConfig = lib.mkMerge [ (mkAfter ''
-
Component "focus.${cfg.hostName}" "client_proxy"
-
target_address = "focus@auth.${cfg.hostName}"
+
extraConfig = lib.mkMerge [
+
(mkAfter ''
+
Component "focus.${cfg.hostName}" "client_proxy"
+
target_address = "focus@auth.${cfg.hostName}"
+
+
Component "speakerstats.${cfg.hostName}" "speakerstats_component"
+
muc_component = "conference.${cfg.hostName}"
+
+
Component "conferenceduration.${cfg.hostName}" "conference_duration_component"
+
muc_component = "conference.${cfg.hostName}"
+
+
Component "endconference.${cfg.hostName}" "end_conference"
+
muc_component = "conference.${cfg.hostName}"
+
+
Component "avmoderation.${cfg.hostName}" "av_moderation_component"
+
muc_component = "conference.${cfg.hostName}"
+
+
Component "metadata.${cfg.hostName}" "room_metadata_component"
+
muc_component = "conference.${cfg.hostName}"
+
breakout_rooms_component = "breakout.${cfg.hostName}"
'')
(mkBefore ''
+
muc_mapper_domain_base = "${cfg.hostName}"
+
cross_domain_websocket = true;
consider_websocket_secure = true;
+
+
unlimited_jids = {
+
"focus@auth.${cfg.hostName}",
+
"jvb@auth.${cfg.hostName}"
+
}
'')
];
virtualHosts.${cfg.hostName} = {
enabled = true;
domain = cfg.hostName;
extraConfig = ''
-
authentication = "anonymous"
+
authentication = ${if cfg.secureDomain.enable then "\"internal_hashed\"" else "\"jitsi-anonymous\""}
c2s_require_encryption = false
admins = { "focus@auth.${cfg.hostName}" }
smacks_max_unacked_stanzas = 5
smacks_hibernation_time = 60
smacks_max_hibernated_sessions = 1
smacks_max_old_sessions = 1
+
+
av_moderation_component = "avmoderation.${cfg.hostName}"
+
speakerstats_component = "speakerstats.${cfg.hostName}"
+
conference_duration_component = "conferenceduration.${cfg.hostName}"
+
end_conference_component = "endconference.${cfg.hostName}"
+
+
c2s_require_encryption = false
+
lobby_muc = "lobby.${cfg.hostName}"
+
breakout_rooms_muc = "breakout.${cfg.hostName}"
+
room_metadata_component = "metadata.${cfg.hostName}"
+
main_muc = "conference.${cfg.hostName}"
'';
ssl = {
cert = "/var/lib/jitsi-meet/jitsi-meet.crt";
···
enabled = true;
domain = "auth.${cfg.hostName}";
extraConfig = ''
-
authentication = "internal_plain"
+
authentication = "internal_hashed"
'';
ssl = {
cert = "/var/lib/jitsi-meet/jitsi-meet.crt";
···
c2s_require_encryption = false
'';
};
+
virtualHosts."guest.${cfg.hostName}" = {
+
enabled = true;
+
domain = "guest.${cfg.hostName}";
+
extraConfig = ''
+
authentication = "anonymous"
+
c2s_require_encryption = false
+
'';
+
};
};
systemd.services.prosody = mkIf cfg.prosody.enable {
preStart = let
···
reloadIfChanged = true;
};
-
users.groups.jitsi-meet = {};
+
users.groups.jitsi-meet = { };
systemd.tmpfiles.rules = [
"d '/var/lib/jitsi-meet' 0750 root jitsi-meet - -"
];
···
'';
};
+
systemd.services.jitsi-excalidraw = mkIf cfg.excalidraw.enable {
+
description = "Excalidraw collaboration backend for Jitsi";
+
after = [ "network.target" ];
+
wantedBy = [ "multi-user.target" ];
+
environment.PORT = toString cfg.excalidraw.port;
+
+
serviceConfig = {
+
Type = "simple";
+
ExecStart = "${pkgs.jitsi-excalidraw}/bin/jitsi-excalidraw-backend";
+
Restart = "on-failure";
+
Group = "jitsi-meet";
+
};
+
};
+
services.nginx = mkIf cfg.nginx.enable {
enable = mkDefault true;
virtualHosts.${cfg.hostName} = {
···
locations."=/external_api.js" = mkDefault {
alias = "${pkgs.jitsi-meet}/libs/external_api.min.js";
};
+
locations."=/_api/room-info" = {
+
proxyPass = "http://localhost:5280/room-info";
+
extraConfig = ''
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
proxy_set_header Host $host;
+
'';
+
};
locations."=/config.js" = mkDefault {
alias = overrideJs "${pkgs.jitsi-meet}/config.js" "config" (recursiveUpdate defaultCfg cfg.config) cfg.extraConfig;
};
locations."=/interface_config.js" = mkDefault {
alias = overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig "";
};
+
locations."/socket.io/" = mkIf cfg.excalidraw.enable {
+
proxyPass = "http://127.0.0.1:${toString cfg.excalidraw.port}";
+
proxyWebsockets = true;
+
};
};
};
···
virtualHosts.${cfg.hostName} = {
extraConfig =
let
-
templatedJitsiMeet = pkgs.runCommand "templated-jitsi-meet" {} ''
+
templatedJitsiMeet = pkgs.runCommand "templated-jitsi-meet" { } ''
cp -R ${pkgs.jitsi-meet}/* .
for file in *.html **/*.html ; do
${pkgs.sd}/bin/sd '<!--#include virtual="(.*)" -->' '{{ include "$1" }}' $file
···
};
};
+
services.jitsi-meet.config = recursiveUpdate
+
(mkIf cfg.excalidraw.enable {
+
whiteboard = {
+
enabled = true;
+
collabServerBaseUrl = "https://${cfg.hostName}";
+
};
+
})
+
(mkIf cfg.secureDomain.enable {
+
hosts.anonymousdomain = "guest.${cfg.hostName}";
+
});
+
services.jitsi-videobridge = mkIf cfg.videobridge.enable {
enable = true;
xmppConfigs."localhost" = {
userName = "jvb";
domain = "auth.${cfg.hostName}";
passwordFile = "/var/lib/jitsi-meet/videobridge-secret";
-
mucJids = "jvbbrewery@internal.${cfg.hostName}";
+
mucJids = "jvbbrewery@internal.auth.${cfg.hostName}";
disableCertificateVerification = true;
};
};
···
userName = "focus";
userPasswordFile = "/var/lib/jitsi-meet/jicofo-user-secret";
componentPasswordFile = "/var/lib/jitsi-meet/jicofo-component-secret";
-
bridgeMuc = "jvbbrewery@internal.${cfg.hostName}";
+
bridgeMuc = "jvbbrewery@internal.auth.${cfg.hostName}";
config = mkMerge [{
jicofo.xmpp.service.disable-certificate-verification = true;
jicofo.xmpp.client.disable-certificate-verification = true;
-
#} (lib.mkIf cfg.jibri.enable {
-
} (lib.mkIf (config.services.jibri.enable || cfg.jibri.enable) {
-
jicofo.jibri = {
-
brewery-jid = "JibriBrewery@internal.${cfg.hostName}";
-
pending-timeout = "90";
-
};
-
})];
+
}
+
(lib.mkIf (config.services.jibri.enable || cfg.jibri.enable) {
+
jicofo.jibri = {
+
brewery-jid = "JibriBrewery@internal.auth.${cfg.hostName}";
+
pending-timeout = "90";
+
};
+
})
+
(lib.mkIf cfg.secureDomain.enable {
+
jicofo = {
+
authentication = {
+
enabled = "true";
+
type = "XMPP";
+
login-url = cfg.hostName;
+
};
+
xmpp.client.client-proxy = "focus.${cfg.hostName}";
+
};
+
})];
};
services.jibri = mkIf cfg.jibri.enable {
···
xmppDomain = cfg.hostName;
control.muc = {
-
domain = "internal.${cfg.hostName}";
+
domain = "internal.auth.${cfg.hostName}";
roomName = "JibriBrewery";
nickname = "jibri";
};
+40
pkgs/servers/jitsi-excalidraw/default.nix
···
+
{ lib
+
, buildNpmPackage
+
, fetchFromGitHub
+
, nodejs
+
, python3
+
}:
+
+
buildNpmPackage rec {
+
pname = "jitsi-excalidraw-backend";
+
version = "17";
+
+
src = fetchFromGitHub {
+
owner = "jitsi";
+
repo = "excalidraw-backend";
+
rev = "x${version}";
+
hash = "sha256-aQePkVA8KRL06VewiD0ePRpj88pAItcV7B2SBnRRtCs=";
+
};
+
+
npmDepsHash = "sha256-BJqjaqTeg5i+ECGMuiBYVToK2i2XCOVP9yeDFz6nP4k=";
+
+
nativeBuildInputs = [ python3 ];
+
+
installPhase = ''
+
mkdir -p $out/share
+
cp -r {node_modules,dist} $out/share
+
'';
+
+
postFixup = ''
+
makeWrapper ${nodejs}/bin/node $out/bin/jitsi-excalidraw-backend \
+
--add-flags dist/index.js \
+
--chdir $out/share
+
'';
+
+
meta = with lib; {
+
description = "Excalidraw collaboration backend for Jitsi";
+
homepage = "https://github.com/jitsi/excalidraw-backend";
+
license = licenses.mit;
+
maintainers = with maintainers; [ camillemndn ];
+
};
+
}
+2
pkgs/top-level/all-packages.nix
···
jicofo = callPackage ../servers/jicofo { };
+
jitsi-excalidraw = callPackage ../servers/jitsi-excalidraw { };
+
jitsi-meet = callPackage ../servers/web-apps/jitsi-meet { };
jitsi-meet-prosody = callPackage ../misc/jitsi-meet-prosody { };