8 cfg = config.services.jitsi-videobridge;
9 attrsToArgs = a: lib.concatStringsSep " " (lib.mapAttrsToList (k: v: "${k}=${toString v}") a);
11 format = pkgs.formats.hocon { };
13 # We're passing passwords in environment variables that have names generated
14 # from an attribute name, which may not be a valid bash identifier.
18 + lib.stringAsChars (c: if builtins.match "[A-Za-z0-9]" c != null then c else "_") s;
31 transports = [ { type = "muc"; } ];
33 apis.xmpp-client.configs = lib.flip lib.mapAttrs cfg.xmppConfigs (
35 hostname = xmppConfig.hostName;
36 domain = xmppConfig.domain;
37 username = xmppConfig.userName;
38 password = format.lib.mkSubstitution (toVarName name);
39 muc_jids = xmppConfig.mucJids;
40 muc_nickname = xmppConfig.mucNickname;
41 disable_certificate_verification = xmppConfig.disableCertificateVerification;
44 apis.rest.enabled = cfg.colibriRestApi;
48 # Allow overriding leaves of the default config despite types.attrs not doing any merging.
49 jvbConfig = lib.recursiveUpdate defaultJvbConfig cfg.config;
53 (lib.mkRemovedOptionModule [ "services" "jitsi-videobridge" "apis" ]
54 "services.jitsi-videobridge.apis was broken and has been migrated into the boolean option services.jitsi-videobridge.colibriRestApi. It is set to false by default, setting it to true will correctly enable the private /colibri rest API."
57 options.services.jitsi-videobridge = with lib.types; {
58 enable = lib.mkEnableOption "Jitsi Videobridge, a WebRTC compatible video router";
60 config = lib.mkOption {
63 example = lib.literalExpression ''
75 Videobridge configuration.
77 See <https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf>
78 for default configuration with comments.
82 xmppConfigs = lib.mkOption {
84 XMPP servers to connect to.
86 See <https://github.com/jitsi/jitsi-videobridge/blob/master/doc/muc.md> for more information.
89 example = lib.literalExpression ''
92 hostName = "localhost";
94 domain = "auth.xmpp.example.org";
95 passwordFile = "/var/lib/jitsi-meet/videobridge-secret";
96 mucJids = "jvbbrewery@internal.xmpp.example.org";
105 hostName = lib.mkOption {
107 example = "xmpp.example.org";
109 Hostname of the XMPP server to connect to. Name of the attribute set is used by default.
112 domain = lib.mkOption {
115 example = "auth.xmpp.example.org";
117 Domain part of JID of the XMPP user, if it is different from hostName.
120 userName = lib.mkOption {
124 User part of the JID.
127 passwordFile = lib.mkOption {
129 example = "/run/keys/jitsi-videobridge-xmpp1";
131 File containing the password for the user.
134 mucJids = lib.mkOption {
136 example = "jvbbrewery@internal.xmpp.example.org";
138 JID of the MUC to join. JiCoFo needs to be configured to join the same MUC.
141 mucNickname = lib.mkOption {
142 # Upstream DEBs use UUID, let's use hostname instead.
145 Videobridges use the same XMPP account and need to be distinguished by the
146 nickname (aka resource part of the JID). By default, system hostname is used.
149 disableCertificateVerification = lib.mkOption {
153 Whether to skip validation of the server's certificate.
158 hostName = lib.mkDefault name;
159 mucNickname = lib.mkDefault (
160 builtins.replaceStrings [ "." ] [ "-" ] (config.networking.fqdnOrHostName)
169 localAddress = lib.mkOption {
172 example = "192.168.1.42";
174 Local address to assume when running behind NAT.
178 publicAddress = lib.mkOption {
183 Public address to assume when running behind NAT.
187 harvesterAddresses = lib.mkOption {
190 "stunserver.stunprotocol.org:3478"
191 "stun.framasoft.org:3478"
192 "meet-jit-si-turnrelay.jitsi.net:443"
196 Addresses of public STUN services to use to automatically find
197 the public and local addresses of this Jitsi-Videobridge instance
198 without the need for manual configuration.
200 This option is ignored if {option}`services.jitsi-videobridge.nat.localAddress`
201 and {option}`services.jitsi-videobridge.nat.publicAddress` are set.
206 extraProperties = lib.mkOption {
210 Additional Java properties passed to jitsi-videobridge.
214 openFirewall = lib.mkOption {
218 Whether to open ports in the firewall for the videobridge.
222 colibriRestApi = lib.mkOption {
225 Whether to enable the private rest API for the COLIBRI control interface.
226 Needed for monitoring jitsi, enabling scraping of the /colibri/stats endpoint.
232 config = lib.mkIf cfg.enable {
233 users.groups.jitsi-meet = { };
235 services.jitsi-videobridge.extraProperties =
236 if (cfg.nat.localAddress != null) then
238 "org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS" = cfg.nat.localAddress;
239 "org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS" = cfg.nat.publicAddress;
243 "org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES" =
244 lib.concatStringsSep "," cfg.nat.harvesterAddresses;
247 systemd.services.jitsi-videobridge2 =
250 "-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
251 "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
252 "-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
253 "-Dconfig.file" = format.generate "jvb.conf" jvbConfig;
254 # Mitigate CVE-2021-44228
255 "-Dlog4j2.formatMsgNoLookups" = true;
256 } // (lib.mapAttrs' (k: v: lib.nameValuePair "-D${k}" v) cfg.extraProperties);
259 aliases = [ "jitsi-videobridge.service" ];
260 description = "Jitsi Videobridge";
261 after = [ "network.target" ];
262 wantedBy = [ "multi-user.target" ];
264 environment.JAVA_SYS_PROPS = attrsToArgs jvbProps;
269 name: xmppConfig: "export ${toVarName name}=$(cat ${xmppConfig.passwordFile})\n"
273 ${pkgs.jitsi-videobridge}/bin/jitsi-videobridge
280 User = "jitsi-videobridge";
281 Group = "jitsi-meet";
283 CapabilityBoundingSet = "";
284 NoNewPrivileges = true;
285 ProtectSystem = "strict";
288 PrivateDevices = true;
289 ProtectHostname = true;
290 ProtectKernelTunables = true;
291 ProtectKernelModules = true;
292 ProtectControlGroups = true;
293 RestrictAddressFamilies = [
298 RestrictNamespaces = true;
299 LockPersonality = true;
300 RestrictRealtime = true;
301 RestrictSUIDSGID = true;
309 environment.etc."jitsi/videobridge/logging.properties".source =
310 lib.mkDefault "${pkgs.jitsi-videobridge}/etc/jitsi/videobridge/logging.properties-journal";
312 # (from videobridge2 .deb)
313 # this sets the max, so that we can bump the JVB UDP single port buffer size.
314 boot.kernel.sysctl."net.core.rmem_max" = lib.mkDefault 10485760;
315 boot.kernel.sysctl."net.core.netdev_max_backlog" = lib.mkDefault 100000;
317 networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [
318 jvbConfig.videobridge.ice.tcp.port
320 networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [
321 jvbConfig.videobridge.ice.udp.port
326 message = "publicAddress must be set if and only if localAddress is set";
327 assertion = (cfg.nat.publicAddress == null) == (cfg.nat.localAddress == null);
332 meta.maintainers = lib.teams.jitsi.members;