Skip to content

Commit 7cd0677

Browse files
authored
nixos/livekit: init, nixos/lk-jwt-service: init (#399627)
2 parents 8ba495f + ba9ab12 commit 7cd0677

File tree

8 files changed

+295
-0
lines changed

8 files changed

+295
-0
lines changed

nixos/modules/module-list.nix

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

nixos/tests/all-tests.nix

+2
Original file line numberDiff line numberDiff line change
@@ -729,11 +729,13 @@ in
729729
lidarr = handleTest ./lidarr.nix { };
730730
lightdm = handleTest ./lightdm.nix { };
731731
lighttpd = runTest ./lighttpd.nix;
732+
livekit = runTest ./networking/livekit.nix;
732733
limesurvey = handleTest ./limesurvey.nix { };
733734
limine = import ./limine { inherit runTest; };
734735
listmonk = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./listmonk.nix { };
735736
litellm = runTest ./litellm.nix;
736737
litestream = handleTest ./litestream.nix { };
738+
lk-jwt-service = runTest ./matrix/lk-jwt-service.nix;
737739
lldap = handleTest ./lldap.nix { };
738740
localsend = handleTest ./localsend.nix { };
739741
locate = handleTest ./locate.nix { };

nixos/tests/matrix/lk-jwt-service.nix

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
pkgs,
3+
lib,
4+
...
5+
}:
6+
{
7+
name = "lk-jwt-service";
8+
meta.maintainers = [ lib.maintainers.quadradical ];
9+
10+
nodes.machine = {
11+
services.lk-jwt-service = {
12+
enable = true;
13+
keyFile = pkgs.writers.writeYAML "keys.yaml" {
14+
key = "f6lQGaHtM5HfgZjIcec3cOCRfiDqIine4CpZZnqdT5cE";
15+
};
16+
livekitUrl = "wss://127.0.0.1:8100";
17+
port = 8000;
18+
};
19+
};
20+
21+
testScript = ''
22+
machine.wait_for_unit("lk-jwt-service.service")
23+
machine.wait_for_open_port(8000)
24+
machine.succeed('curl 127.0.0.1:8000/sfu/get -sLX POST -w "%{http_code}" | grep -q "^400"')
25+
'';
26+
}

nixos/tests/networking/livekit.nix

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
pkgs,
3+
lib,
4+
...
5+
}:
6+
{
7+
name = "livekit";
8+
meta.maintainers = [ lib.maintainers.quadradical ];
9+
10+
nodes.machine = {
11+
services.livekit = {
12+
enable = true;
13+
keyFile = pkgs.writers.writeYAML "keys.yaml" {
14+
key = "f6lQGaHtM5HfgZjIcec3cOCRfiDqIine4CpZZnqdT5cE";
15+
};
16+
settings.port = 8000;
17+
};
18+
};
19+
20+
testScript = ''
21+
machine.wait_for_unit("livekit.service")
22+
machine.wait_for_open_port(8000)
23+
machine.succeed("curl 127.0.0.1:8000 -L --fail")
24+
'';
25+
}

pkgs/by-name/li/livekit/package.nix

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
lib,
33
buildGoModule,
44
fetchFromGitHub,
5+
nixosTests,
56
}:
67

78
buildGoModule rec {
@@ -23,6 +24,8 @@ buildGoModule rec {
2324
mv $out/bin/server $out/bin/livekit-server
2425
'';
2526

27+
passthru.tests = nixosTests.livekit;
28+
2629
meta = with lib; {
2730
description = "End-to-end stack for WebRTC. SFU media server and SDKs";
2831
homepage = "https://livekit.io/";

pkgs/by-name/lk/lk-jwt-service/package.nix

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
lib,
33
buildGoModule,
44
fetchFromGitHub,
5+
nixosTests,
56
}:
67

78
buildGoModule (finalAttrs: {
@@ -17,6 +18,8 @@ buildGoModule (finalAttrs: {
1718

1819
vendorHash = "sha256-47eJO1Ai78RuhlEPn/J1cd+YSqvmfUD8cuPZIqsdxvI=";
1920

21+
passthru.tests = nixosTests.lk-jwt-service;
22+
2023
meta = with lib; {
2124
changelog = "https://github.com/element-hq/lk-jwt-service/releases/tag/${finalAttrs.src.tag}";
2225
description = "Minimal service to issue LiveKit JWTs for MatrixRTC";

0 commit comments

Comments
 (0)