diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 3b374a34ac9..07405e4a416 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -642,6 +642,7 @@
./services/networking/iperf3.nix
./services/networking/ircd-hybrid/default.nix
./services/networking/iwd.nix
+ ./services/networking/jicofo.nix
./services/networking/jitsi-videobridge.nix
./services/networking/keepalived/default.nix
./services/networking/keybase.nix
diff --git a/nixos/modules/services/networking/jicofo.nix b/nixos/modules/services/networking/jicofo.nix
new file mode 100644
index 00000000000..64e57eef97f
--- /dev/null
+++ b/nixos/modules/services/networking/jicofo.nix
@@ -0,0 +1,152 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.jicofo;
+in
+{
+ options.services.jicofo = with types; {
+ enable = mkEnableOption "Jitsi Conference Focus - component of Jitsi Meet";
+
+ xmppHost = mkOption {
+ type = str;
+ example = "localhost";
+ description = ''
+ Hostname of the XMPP server to connect to.
+ '';
+ };
+
+ xmppDomain = mkOption {
+ type = nullOr str;
+ example = "meet.example.org";
+ description = ''
+ Domain name of the XMMP server to which to connect as a component.
+
+ If null, is used.
+ '';
+ };
+
+ componentPasswordFile = mkOption {
+ type = str;
+ example = "/run/keys/jicofo-component";
+ description = ''
+ Path to file containing component secret.
+ '';
+ };
+
+ userName = mkOption {
+ type = str;
+ default = "focus";
+ description = ''
+ User part of the JID for XMPP user connection.
+ '';
+ };
+
+ userDomain = mkOption {
+ type = str;
+ example = "auth.meet.example.org";
+ description = ''
+ Domain part of the JID for XMPP user connection.
+ '';
+ };
+
+ userPasswordFile = mkOption {
+ type = str;
+ example = "/run/keys/jicofo-user";
+ description = ''
+ Path to file containing password for XMPP user connection.
+ '';
+ };
+
+ bridgeMuc = mkOption {
+ type = str;
+ example = "jvbbrewery@internal.meet.example.org";
+ description = ''
+ JID of the internal MUC used to communicate with Videobridges.
+ '';
+ };
+
+ config = mkOption {
+ type = attrsOf str;
+ default = { };
+ example = literalExample ''
+ {
+ "org.jitsi.jicofo.auth.URL" = "XMPP:jitsi-meet.example.com";
+ }
+ '';
+ description = ''
+ Contents of the sip-communicator.properties configuration file for jicofo.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.jicofo.config = mapAttrs (_: v: mkDefault v) {
+ "org.jitsi.jicofo.BRIDGE_MUC" = cfg.bridgeMuc;
+ };
+
+ users.groups.jitsi-meet = {};
+
+ systemd.services.jicofo = let
+ jicofoProps = {
+ "-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
+ "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "jicofo";
+ "-Djava.util.logging.config.file" = "/etc/jitsi/jicofo/logging.properties";
+ };
+ in
+ {
+ description = "JItsi COnference FOcus";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+
+ restartTriggers = [
+ config.environment.etc."jitsi/jicofo/sip-communicator.properties".source
+ ];
+ environment.JAVA_SYS_PROPS = concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") jicofoProps);
+
+ script = ''
+ ${pkgs.jicofo}/bin/jicofo \
+ --host=${cfg.xmppHost} \
+ --domain=${if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain} \
+ --secret=$(cat ${cfg.componentPasswordFile}) \
+ --user_name=${cfg.userName} \
+ --user_domain=${cfg.userDomain} \
+ --user_password=$(cat ${cfg.userPasswordFile})
+ '';
+
+ serviceConfig = {
+ Type = "exec";
+
+ DynamicUser = true;
+ User = "jicofo";
+ Group = "jitsi-meet";
+
+ CapabilityBoundingSet = "";
+ NoNewPrivileges = true;
+ ProtectSystem = "strict";
+ ProtectHome = true;
+ PrivateTmp = true;
+ PrivateDevices = true;
+ ProtectHostname = true;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
+ RestrictNamespaces = true;
+ LockPersonality = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ };
+ };
+
+ environment.etc."jitsi/jicofo/sip-communicator.properties".source =
+ pkgs.writeText "sip-communicator.properties" (
+ concatStringsSep "\n" (mapAttrsToList (k: v: "${k}=${v}") cfg.config)
+ );
+ environment.etc."jitsi/jicofo/logging.properties".source =
+ mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal";
+ };
+
+ meta.maintainers = with lib.maintainers; [ ];
+}