at master 6.2 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 utils, 6 ... 7}: 8let 9 cfg = config.services.livekit; 10 format = pkgs.formats.json { }; 11 settings = lib.filterAttrsRecursive (_: v: v != null) cfg.settings; 12 13 isLocallyDistributed = config.services.livekit.ingress.enable; 14in 15{ 16 meta.maintainers = with lib.maintainers; [ quadradical ]; 17 options.services.livekit = { 18 enable = lib.mkEnableOption "the livekit server"; 19 package = lib.mkPackageOption pkgs "livekit" { }; 20 21 keyFile = lib.mkOption { 22 type = lib.types.path; 23 description = '' 24 LiveKit key file holding one or multiple application secrets. Use `livekit-server generate-keys` to generate a random key name and secret. 25 26 The file should have the format `<keyname>: <secret>`. 27 Example: 28 `lk-jwt-service: f6lQGaHtM5HfgZjIcec3cOCRfiDqIine4CpZZnqdT5cE` 29 30 Individual key/secret pairs need to be passed to clients to connect to this instance. 31 ''; 32 }; 33 34 openFirewall = lib.mkOption { 35 type = lib.types.bool; 36 default = false; 37 description = "Opens port range for LiveKit on the firewall."; 38 }; 39 40 redis = { 41 createLocally = lib.mkOption { 42 type = lib.types.bool; 43 default = isLocallyDistributed; 44 defaultText = "true if any other Livekit component is enabled locally else false"; 45 description = "Whether to set up a local redis instance."; 46 }; 47 48 host = lib.mkOption { 49 type = with lib.types; nullOr str; 50 default = if cfg.redis.createLocally then "127.0.0.1" else null; 51 defaultText = "127.0.0.1 if config.services.livekit.redis.createLocally else null"; 52 description = '' 53 Address to bind local redis instance to. 54 ''; 55 }; 56 57 port = lib.mkOption { 58 type = with lib.types; nullOr port; 59 default = null; 60 description = '' 61 Port to bind local redis instance to. 62 ''; 63 }; 64 }; 65 66 settings = lib.mkOption { 67 type = lib.types.submodule { 68 freeformType = format.type; 69 options = { 70 port = lib.mkOption { 71 type = lib.types.port; 72 default = 7880; 73 description = "Main TCP port for RoomService and RTC endpoint."; 74 }; 75 76 redis = { 77 address = lib.mkOption { 78 type = with lib.types; nullOr str; 79 default = if isLocallyDistributed then "${cfg.redis.host}:${toString cfg.redis.port}" else null; 80 defaultText = lib.literalExpression "Local Redis host/port when a local ingress component is enabled else null"; 81 example = "redis.example.com:6379"; 82 description = "Host and port used to connect to a redis instance."; 83 }; 84 }; 85 86 rtc = { 87 port_range_start = lib.mkOption { 88 type = lib.types.port; 89 default = 50000; 90 description = "Start of UDP port range for WebRTC"; 91 }; 92 93 port_range_end = lib.mkOption { 94 type = lib.types.port; 95 default = 51000; 96 description = "End of UDP port range for WebRTC"; 97 }; 98 99 use_external_ip = lib.mkOption { 100 type = lib.types.bool; 101 default = false; 102 description = '' 103 When set to true, attempts to discover the host's public IP via STUN. 104 This is useful for cloud environments such as AWS & Google where hosts have an internal IP that maps to an external one. 105 ''; 106 }; 107 }; 108 }; 109 }; 110 default = { }; 111 description = '' 112 LiveKit configuration file expressed in nix. 113 114 For an example configuration, see <https://docs.livekit.io/home/self-hosting/deployment/#configuration>. 115 For all possible values, see <https://github.com/livekit/livekit/blob/master/config-sample.yaml>. 116 ''; 117 }; 118 }; 119 120 config = lib.mkIf cfg.enable { 121 assertions = [ 122 { 123 assertion = cfg.redis.createLocally -> cfg.redis.port != null; 124 message = '' 125 When `services.livekit.redis.createLocally` is enabled `services.livekit.redis.port` must be configured. 126 ''; 127 } 128 ]; 129 130 networking.firewall = lib.mkIf cfg.openFirewall { 131 allowedTCPPorts = [ 132 cfg.settings.port 133 ]; 134 allowedUDPPortRanges = [ 135 { 136 from = cfg.settings.rtc.port_range_start; 137 to = cfg.settings.rtc.port_range_end; 138 } 139 ]; 140 }; 141 142 # Provision a redis instance, when livekit-ingress (or later livekit-egress) are enabled on the same host 143 services.redis.servers.livekit = lib.mkIf cfg.redis.createLocally { 144 enable = true; 145 bind = cfg.redis.host; 146 port = cfg.redis.port; 147 }; 148 149 systemd.services.livekit = { 150 description = "LiveKit SFU server"; 151 documentation = [ "https://docs.livekit.io" ]; 152 wantedBy = [ "multi-user.target" ]; 153 wants = [ "network-online.target" ]; 154 after = [ "network-online.target" ]; 155 156 serviceConfig = { 157 LoadCredential = [ "livekit-secrets:${cfg.keyFile}" ]; 158 ExecStart = utils.escapeSystemdExecArgs [ 159 (lib.getExe cfg.package) 160 "--config=${format.generate "livekit.json" settings}" 161 "--key-file=/run/credentials/livekit.service/livekit-secrets" 162 ]; 163 DynamicUser = true; 164 LockPersonality = true; 165 MemoryDenyWriteExecute = true; 166 ProtectClock = true; 167 ProtectControlGroups = true; 168 ProtectHostname = true; 169 ProtectKernelLogs = true; 170 ProtectKernelModules = true; 171 ProtectKernelTunables = true; 172 PrivateDevices = true; 173 PrivateMounts = true; 174 PrivateUsers = true; 175 RestrictAddressFamilies = [ 176 "AF_INET" 177 "AF_INET6" 178 "AF_NETLINK" 179 ]; 180 RestrictNamespaces = true; 181 RestrictRealtime = true; 182 ProtectHome = true; 183 SystemCallArchitectures = "native"; 184 SystemCallFilter = [ 185 "@system-service" 186 "~@privileged" 187 "~@resources" 188 ]; 189 Restart = "on-failure"; 190 RestartSec = 5; 191 UMask = "077"; 192 }; 193 }; 194 }; 195}