mirror of https://gitlab.crans.org/nounous/nixos
Adding a coturn VM
parent
5db5253d03
commit
12fb12ce6b
|
|
@ -50,6 +50,11 @@
|
||||||
modules = [ ./hosts/vm/collabora ] ++ baseModules;
|
modules = [ ./hosts/vm/collabora ] ++ baseModules;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
coturn = nixosSystem {
|
||||||
|
specialArgs = inputs;
|
||||||
|
modules = [ ./hosts/vm/coturn ] ++ baseModules;
|
||||||
|
};
|
||||||
|
|
||||||
jitsi = nixosSystem {
|
jitsi = nixosSystem {
|
||||||
specialArgs = inputs;
|
specialArgs = inputs;
|
||||||
modules = [ ./hosts/vm/jitsi ] ++ baseModules;
|
modules = [ ./hosts/vm/jitsi ] ++ baseModules;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
age.secrets = {
|
||||||
|
coturn_auth_secret = {
|
||||||
|
file = ../../../secrets/common/coturn_auth_secret.age;
|
||||||
|
mode = "440";
|
||||||
|
owner = "turnserver";
|
||||||
|
group = "turnserver";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Taken from https://wiki.nixos.org/wiki/Matrix#Coturn_with_Synapse
|
||||||
|
services.coturn = rec {
|
||||||
|
enable = true;
|
||||||
|
no-cli = true;
|
||||||
|
no-tcp-relay = true;
|
||||||
|
min-port = 48000;
|
||||||
|
max-port = 50000;
|
||||||
|
use-auth-secret = true;
|
||||||
|
static-auth-secret-file = config.age.secrets.coturn_auth_secret.path;
|
||||||
|
secure-stun = true;
|
||||||
|
realm = "coturn.crans.org";
|
||||||
|
cert = "${config.security.acme.certs.${realm}.directory}/full.pem";
|
||||||
|
pkey = "${config.security.acme.certs.${realm}.directory}/key.pem";
|
||||||
|
extraConfig = ''
|
||||||
|
# for debugging
|
||||||
|
verbose
|
||||||
|
# ban private IP ranges
|
||||||
|
no-multicast-peers
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall =
|
||||||
|
let
|
||||||
|
range = with config.services.coturn; lib.singleton {
|
||||||
|
from = min-port;
|
||||||
|
to = max-port;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
allowedUDPPortRanges = range;
|
||||||
|
allowedUDPPorts = [ 3478 5349 ];
|
||||||
|
allowedTCPPortRanges = range;
|
||||||
|
allowedTCPPorts = [ 3478 5349 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.turnserver.extraGroups = [ "nginx" ];
|
||||||
|
|
||||||
|
security.acme.certs.${config.services.coturn.realm} = {
|
||||||
|
postRun = "systemctl restart coturn.service";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts = {
|
||||||
|
${config.services.coturn.realm} = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# services.matrix-synapse.settings = with config.services.coturn; {
|
||||||
|
# turn_uris = ["turn:${realm}:3478?transport=udp" "turn:${realm}:3478?transport=tcp"];
|
||||||
|
# turn_shared_secret = static-auth-secret;
|
||||||
|
# turn_user_lifetime = "1h";
|
||||||
|
# };
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
# ./coturn.nix
|
||||||
|
# ./livekit.nix
|
||||||
|
./hardware-configuration.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.hostName = "coturn";
|
||||||
|
boot.loader.grub.devices = [ "/dev/sda" ];
|
||||||
|
|
||||||
|
crans = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
id = 119;
|
||||||
|
srv = {
|
||||||
|
enable = true;
|
||||||
|
ipv4 = "185.230.79.19";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.acme.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
resticClient.when = "06:07";
|
||||||
|
};
|
||||||
|
|
||||||
|
system.stateVersion = "26.05";
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||||
|
# and may be overwritten by future invocations. Please make changes
|
||||||
|
# to /etc/nixos/configuration.nix instead.
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/profiles/qemu-guest.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"ata_piix"
|
||||||
|
"uhci_hcd"
|
||||||
|
"virtio_pci"
|
||||||
|
"virtio_scsi"
|
||||||
|
"sd_mod"
|
||||||
|
"sr_mod"
|
||||||
|
];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-uuid/e2406ee7-b3ca-4fe0-8b4b-e4a38a1149ca";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||||
|
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||||
|
# still possible to use this option, but it's recommended to use it in conjunction
|
||||||
|
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||||
|
networking.useDHCP = lib.mkDefault true;
|
||||||
|
# networking.interfaces.ens18.useDHCP = lib.mkDefault true;
|
||||||
|
# networking.interfaces.ens19.useDHCP = lib.mkDefault true;
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
keyFile = "/run/livekit.key";
|
||||||
|
domain = "livekit.crans.org";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.livekit' = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
openFirewall = true;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
port = 8100;
|
||||||
|
|
||||||
|
room.auto_create = true;
|
||||||
|
|
||||||
|
rtc = {
|
||||||
|
use_external_ip = false;
|
||||||
|
node_ip = config.crans.networking.srv.ipv4;
|
||||||
|
tcp_port = 8101;
|
||||||
|
port_range_start = 50000;
|
||||||
|
port_range_end = 52000;
|
||||||
|
enable_loopback_candidate = false;
|
||||||
|
turn_servers = [
|
||||||
|
{
|
||||||
|
host = config.services.coturn.realm;
|
||||||
|
port = 3478;
|
||||||
|
protocol = "tcp";
|
||||||
|
secretFile = config.age.secrets.coturn_auth_secret.path;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = config.services.coturn.realm;
|
||||||
|
port = 3478;
|
||||||
|
protocol = "udp";
|
||||||
|
secretFile = config.age.secrets.coturn_auth_secret.path;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = config.services.coturn.realm;
|
||||||
|
port = 5349;
|
||||||
|
protocol = "tls";
|
||||||
|
secretFile = config.age.secrets.coturn_auth_secret.path;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
turn.enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
inherit keyFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall =
|
||||||
|
let
|
||||||
|
range = with config.services.livekit'.settings.rtc; lib.singleton {
|
||||||
|
from = port_range_start;
|
||||||
|
to = port_range_end;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
allowedUDPPortRanges = range;
|
||||||
|
allowedUDPPorts = [ 8100 8101 8102 ];
|
||||||
|
allowedTCPPortRanges = range;
|
||||||
|
allowedTCPPorts = [ 8100 8101 8102 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.livekit.extraGroups = [ "turnserver" ];
|
||||||
|
|
||||||
|
services.lk-jwt-service = {
|
||||||
|
enable = true;
|
||||||
|
port = 8102;
|
||||||
|
|
||||||
|
livekitUrl = "wss://${domain}";
|
||||||
|
|
||||||
|
inherit keyFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.livekit-key = {
|
||||||
|
before = [
|
||||||
|
"lk-jwt-service.service"
|
||||||
|
"livekit.service"
|
||||||
|
];
|
||||||
|
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
path = with pkgs; [
|
||||||
|
livekit
|
||||||
|
coreutils
|
||||||
|
gawk
|
||||||
|
];
|
||||||
|
|
||||||
|
script = ''
|
||||||
|
echo "Key missing, generating key"
|
||||||
|
echo "lk-jwt-service: $(livekit-server generate-keys | tail -1 | awk '{print $3}')" > "${keyFile}"
|
||||||
|
'';
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
unitConfig.ConditionPathExists = "!${keyFile}";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.lk-jwt-service.environment.LIVEKIT_FULL_ACCESS_HOMESERVERS = "crans.org";
|
||||||
|
|
||||||
|
services.nginx.virtualHosts."${domain}" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
|
||||||
|
locations."~ /(get_token|healthz|sfu/get)" = {
|
||||||
|
proxyPass = "http://localhost:${toString config.services.lk-jwt-service.port}";
|
||||||
|
};
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://localhost:${toString config.services.livekit'.settings.port}";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
age.secrets = {
|
||||||
|
autofocus-config = {
|
||||||
|
file = ../../../secrets/zora/services/autofocus-config.age;
|
||||||
|
mode = "444";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -25,10 +25,7 @@
|
||||||
|
|
||||||
resticClient.when = "04:56";
|
resticClient.when = "04:56";
|
||||||
|
|
||||||
services = {
|
services.acme.enable = true;
|
||||||
acme.enable = true;
|
|
||||||
coturn.enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
system.stateVersion = "24.11";
|
system.stateVersion = "24.11";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
turn_server = "coturn.crans.org";
|
||||||
|
in
|
||||||
{
|
{
|
||||||
age.secrets = {
|
age.secrets = {
|
||||||
ldap_synapse_password = {
|
ldap_synapse_password = {
|
||||||
|
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
{ config, lib, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.crans.services.coturn;
|
|
||||||
|
|
||||||
inherit (lib)
|
|
||||||
mkEnableOption
|
|
||||||
mkOption
|
|
||||||
mkIf
|
|
||||||
types
|
|
||||||
;
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
options.crans.services.coturn = {
|
|
||||||
enable = mkEnableOption "Coturn, un serveur TURN open-source.";
|
|
||||||
|
|
||||||
secretFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = config.age.secrets.coturn_auth_secret.path;
|
|
||||||
description = "Fichier contenant le secret de configuration du serveur.";
|
|
||||||
};
|
|
||||||
|
|
||||||
fqdn = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "crans.org";
|
|
||||||
description = "Domaine pour lequel le serveur coturn est configuré.";
|
|
||||||
};
|
|
||||||
|
|
||||||
certFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/lib/acme/${cfg.fqdn}/full.pem";
|
|
||||||
description = "Fichier contenant le certificat associé au FQDN.";
|
|
||||||
};
|
|
||||||
|
|
||||||
keyFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/lib/acme/${cfg.fqdn}/key.pem";
|
|
||||||
description = "Fichier contenant la clef associé au FQDN.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
services.coturn = {
|
|
||||||
enable = true;
|
|
||||||
no-cli = true;
|
|
||||||
no-tcp-relay = true;
|
|
||||||
min-port = 49000;
|
|
||||||
max-port = 50000;
|
|
||||||
use-auth-secret = true;
|
|
||||||
static-auth-secret-file = cfg.secretFile;
|
|
||||||
realm = cfg.fqdn;
|
|
||||||
cert = cfg.certFile;
|
|
||||||
pkey = cfg.keyFile;
|
|
||||||
extraConfig = ''
|
|
||||||
verbose
|
|
||||||
no-multicast-peers
|
|
||||||
denied-peer-ip=0.0.0.0-0.255.255.255
|
|
||||||
denied-peer-ip=10.0.0.0-10.255.255.255
|
|
||||||
denied-peer-ip=100.64.0.0-100.127.255.255
|
|
||||||
denied-peer-ip=127.0.0.0-127.255.255.255
|
|
||||||
denied-peer-ip=169.254.0.0-169.254.255.255
|
|
||||||
denied-peer-ip=172.16.0.0-172.31.255.255
|
|
||||||
denied-peer-ip=192.0.0.0-192.0.0.255
|
|
||||||
denied-peer-ip=192.0.2.0-192.0.2.255
|
|
||||||
denied-peer-ip=192.88.99.0-192.88.99.255
|
|
||||||
denied-peer-ip=192.168.0.0-192.168.255.255
|
|
||||||
denied-peer-ip=198.18.0.0-198.19.255.255
|
|
||||||
denied-peer-ip=198.51.100.0-198.51.100.255
|
|
||||||
denied-peer-ip=203.0.113.0-203.0.113.255
|
|
||||||
denied-peer-ip=240.0.0.0-255.255.255.255
|
|
||||||
denied-peer-ip=::1
|
|
||||||
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
|
|
||||||
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
|
|
||||||
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
|
|
||||||
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
|
|
||||||
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
|
||||||
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
|
||||||
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall = {
|
|
||||||
allowedTCPPorts = [
|
|
||||||
3478
|
|
||||||
5349
|
|
||||||
];
|
|
||||||
allowedUDPPorts = [
|
|
||||||
3478
|
|
||||||
5349
|
|
||||||
];
|
|
||||||
allowedUDPPortRanges = [
|
|
||||||
{
|
|
||||||
from = config.services.coturn.min-port;
|
|
||||||
to = config.services.coturn.max-port;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./acme.nix
|
./acme.nix
|
||||||
./coturn.nix
|
./livekit.nix
|
||||||
./nginx.nix
|
./nginx.nix
|
||||||
./restic.nix
|
./restic.nix
|
||||||
./reverseproxy.nix
|
./reverseproxy.nix
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,253 @@
|
||||||
|
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
turn_servers = lib.mkOption {
|
||||||
|
type = lib.types.listOf (lib.types.submodule {
|
||||||
|
freeformType = format.type;
|
||||||
|
options = {
|
||||||
|
secretFile = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = ''
|
||||||
|
Path to a file containing the shared secret of a coturn server.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
default = [];
|
||||||
|
example = [
|
||||||
|
{
|
||||||
|
host = "coturn.example.com";
|
||||||
|
port = 443;
|
||||||
|
protocol = "tls";
|
||||||
|
secretFile = "/run/turn_secret";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
An attribute set of turn servers.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
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 = {
|
||||||
|
tmpfiles.settings.livekit = {
|
||||||
|
"/run/livekit-config.json"."f" = {
|
||||||
|
mode = "600";
|
||||||
|
user = "livekit";
|
||||||
|
group = "livekit";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.livekit = {
|
||||||
|
description = "LiveKit SFU server";
|
||||||
|
documentation = [ "https://docs.livekit.io" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
|
||||||
|
preStart =
|
||||||
|
let
|
||||||
|
file = "/run/livekit-config.json";
|
||||||
|
in
|
||||||
|
''
|
||||||
|
cat ${format.generate "livekit.json" settings} > ${file}
|
||||||
|
while $(cat ${file} | ${pkgs.jq}/bin/jq -e 'first((.rtc.turn_servers[]) | select(.secretFile != null)).secretFile != null')
|
||||||
|
do
|
||||||
|
secretFile=$(cat ${file} | ${pkgs.jq}/bin/jq -r 'first((.rtc.turn_servers[]) | select(.secretFile != null)).secretFile')
|
||||||
|
cat ${file} | ${pkgs.jq}/bin/jq "first((.rtc.turn_servers[]) | select(.secretFile != null)).secret = \"$(cat $secretFile)\" | del(first((.rtc.turn_servers[]) | select(.secretFile != null)).secretFile)" > ${file}
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
User = "livekit";
|
||||||
|
Group = "livekit";
|
||||||
|
LoadCredential = [ "livekit-secrets:${cfg.keyFile}" ];
|
||||||
|
ExecStart = utils.escapeSystemdExecArgs [
|
||||||
|
(lib.getExe cfg.package)
|
||||||
|
"--config=/run/livekit-config.json"
|
||||||
|
"--key-file=/run/credentials/livekit.service/livekit-secrets"
|
||||||
|
];
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users = {
|
||||||
|
users.livekit = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "livekit";
|
||||||
|
};
|
||||||
|
groups.livekit = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -38,6 +38,7 @@ let
|
||||||
apprentix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCJV6jqQWEYuwi+OJ9r/4TbBN/cK9NvYWNiJhpFzcc7 root@apprentix";
|
apprentix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCJV6jqQWEYuwi+OJ9r/4TbBN/cK9NvYWNiJhpFzcc7 root@apprentix";
|
||||||
cephiroth = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOsBGkhiu6l3jeo15cQHMu3dPyL025zXPV2ZH02EDYEt root@nixos";
|
cephiroth = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOsBGkhiu6l3jeo15cQHMu3dPyL025zXPV2ZH02EDYEt root@nixos";
|
||||||
collabora = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFa2D9fREtO2r2oIx6q9JAKFUHtxGbgEPMjkx09DQSU8 root@collabora";
|
collabora = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFa2D9fREtO2r2oIx6q9JAKFUHtxGbgEPMjkx09DQSU8 root@collabora";
|
||||||
|
# coturn = "";
|
||||||
jitsi = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6jVMIZ5y2oXX9HOkw7r5UUjw95MlFaFuu7FnEC0Q8z root@jitsi";
|
jitsi = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6jVMIZ5y2oXX9HOkw7r5UUjw95MlFaFuu7FnEC0Q8z root@jitsi";
|
||||||
livre = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEVfKNokHG6ig32hhQxTep+fKFmKahlDClPrX/dP4/gb root@livre";
|
livre = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEVfKNokHG6ig32hhQxTep+fKFmKahlDClPrX/dP4/gb root@livre";
|
||||||
neo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMGfSvxqC2PJYRrxJaivVDujwlwCZ6AwH8hOSA9ktZ1V root@neo";
|
neo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMGfSvxqC2PJYRrxJaivVDujwlwCZ6AwH8hOSA9ktZ1V root@neo";
|
||||||
|
|
@ -55,6 +56,7 @@ let
|
||||||
all = attrsets.mapAttrsToList (_: key: key) hosts;
|
all = attrsets.mapAttrsToList (_: key: key) hosts;
|
||||||
|
|
||||||
acme = [
|
acme = [
|
||||||
|
# hosts.coturn
|
||||||
hosts.jitsi
|
hosts.jitsi
|
||||||
hosts.neo
|
hosts.neo
|
||||||
hosts.reverseproxy
|
hosts.reverseproxy
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue