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