1{
2 config,
3 lib,
4 pkgs,
5 utils,
6 ...
7}:
8let
9 cfg = config.services.livekit;
10 format = pkgs.formats.json { };
11in
12{
13 meta.maintainers = with lib.maintainers; [ quadradical ];
14 options.services.livekit = {
15 enable = lib.mkEnableOption "the livekit server";
16 package = lib.mkPackageOption pkgs "livekit" { };
17
18 keyFile = lib.mkOption {
19 type = lib.types.path;
20 description = ''
21 LiveKit key file holding one or multiple application secrets. Use `livekit-server generate-keys` to generate a random key name and secret.
22
23 The file should have the format `<keyname>: <secret>`.
24 Example:
25 `lk-jwt-service: f6lQGaHtM5HfgZjIcec3cOCRfiDqIine4CpZZnqdT5cE`
26
27 Individual key/secret pairs need to be passed to clients to connect to this instance.
28 '';
29 };
30
31 openFirewall = lib.mkOption {
32 type = lib.types.bool;
33 default = false;
34 description = "Opens port range for LiveKit on the firewall.";
35 };
36
37 settings = lib.mkOption {
38 type = lib.types.submodule {
39 freeformType = format.type;
40 options = {
41 port = lib.mkOption {
42 type = lib.types.port;
43 default = 7880;
44 description = "Main TCP port for RoomService and RTC endpoint.";
45 };
46
47 rtc = {
48 port_range_start = lib.mkOption {
49 type = lib.types.int;
50 default = 50000;
51 description = "Start of UDP port range for WebRTC";
52 };
53
54 port_range_end = lib.mkOption {
55 type = lib.types.int;
56 default = 51000;
57 description = "End of UDP port range for WebRTC";
58 };
59
60 use_external_ip = lib.mkOption {
61 type = lib.types.bool;
62 default = false;
63 description = ''
64 When set to true, attempts to discover the host's public IP via STUN.
65 This is useful for cloud environments such as AWS & Google where hosts have an internal IP that maps to an external one.
66 '';
67 };
68 };
69 };
70 };
71 default = { };
72 description = ''
73 LiveKit configuration file expressed in nix.
74
75 For an example configuration, see <https://docs.livekit.io/home/self-hosting/deployment/#configuration>.
76 For all possible values, see <https://github.com/livekit/livekit/blob/master/config-sample.yaml>.
77 '';
78 };
79 };
80
81 config = lib.mkIf cfg.enable {
82 networking.firewall = lib.mkIf cfg.openFirewall {
83 allowedTCPPorts = [
84 cfg.settings.port
85 ];
86 allowedUDPPortRanges = [
87 {
88 from = cfg.settings.rtc.port_range_start;
89 to = cfg.settings.rtc.port_range_end;
90 }
91 ];
92 };
93
94 systemd.services.livekit = {
95 description = "LiveKit SFU server";
96 documentation = [ "https://docs.livekit.io" ];
97 wantedBy = [ "multi-user.target" ];
98 wants = [ "network-online.target" ];
99 after = [ "network-online.target" ];
100
101 serviceConfig = {
102 LoadCredential = [ "livekit-secrets:${cfg.keyFile}" ];
103 ExecStart = utils.escapeSystemdExecArgs [
104 (lib.getExe cfg.package)
105 "--config=${format.generate "livekit.json" cfg.settings}"
106 "--key-file=/run/credentials/livekit.service/livekit-secrets"
107 ];
108 DynamicUser = true;
109 LockPersonality = true;
110 MemoryDenyWriteExecute = true;
111 ProtectClock = true;
112 ProtectControlGroups = true;
113 ProtectHostname = true;
114 ProtectKernelLogs = true;
115 ProtectKernelModules = true;
116 ProtectKernelTunables = true;
117 PrivateDevices = true;
118 PrivateMounts = true;
119 PrivateUsers = true;
120 RestrictAddressFamilies = [
121 "AF_INET"
122 "AF_INET6"
123 "AF_NETLINK"
124 ];
125 RestrictNamespaces = true;
126 RestrictRealtime = true;
127 ProtectHome = true;
128 SystemCallArchitectures = "native";
129 SystemCallFilter = [
130 "@system-service"
131 "~@privileged"
132 "~@resources"
133 ];
134 Restart = "on-failure";
135 RestartSec = 5;
136 UMask = "077";
137 };
138 };
139 };
140}