some jitsi shit

This commit is contained in:
2026-03-23 19:22:40 +00:00
parent 62b7742ef0
commit 2513b76658
4 changed files with 238 additions and 7 deletions

View File

@@ -0,0 +1,97 @@
{
inputs,
flake,
self,
}:
{
pkgs,
lib,
config,
...
}: let
cfg = config.hectic.services.jitsi;
in {
options = {
hectic.services.jitsi = {
enable = lib.mkEnableOption "Jitsi Meet video conferencing with Prosody XMPP backend";
hostName = lib.mkOption {
type = lib.types.str;
description = ''
FQDN for the Jitsi Meet instance (e.g. "meet.example.org").
Prosody VirtualHosts, nginx, and ACME certs are derived from this.
'';
};
secureDomain = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Require authentication to create rooms. Guests can still join
existing rooms anonymously.
'';
};
lockdown = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Restrict Prosody to localhost only (no S2S federation, c2s
only on 127.0.0.1). Set to false when running alongside a
general-purpose XMPP server (hectic.services.xmpp).
'';
};
videobridgePasswordFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to a file containing the Jitsi Videobridge XMPP password.
If null, a random password is auto-generated.
'';
};
};
};
config = lib.mkIf cfg.enable {
services.jitsi-meet = {
enable = true;
hostName = cfg.hostName;
prosody = {
enable = true;
lockdown = cfg.lockdown;
};
nginx.enable = true;
videobridge = {
enable = true;
} // lib.optionalAttrs (cfg.videobridgePasswordFile != null) {
passwordFile = cfg.videobridgePasswordFile;
};
jicofo.enable = true;
secureDomain = lib.mkIf cfg.secureDomain {
enable = true;
};
};
services.jitsi-videobridge.openFirewall = true;
services.nginx.virtualHosts.${cfg.hostName} = {
enableACME = true;
forceSSL = true;
};
security.acme = {
acceptTerms = true;
defaults = {
email = "hectic.yukkop.it@gmail.com";
enableDebugLogs = true;
};
};
networking.firewall = {
allowedTCPPorts = [
80 443 # HTTP/HTTPS (nginx + ACME)
5222 # XMPP c2s (if not locked down)
];
};
};
}

View File

@@ -0,0 +1,119 @@
{
inputs,
flake,
self,
}:
{
pkgs,
lib,
config,
...
}: let
cfg = config.hectic.services.xmpp;
in {
options = {
hectic.services.xmpp = {
enable = lib.mkEnableOption "General-purpose XMPP server (Prosody) for messaging clients like Monocles Chat";
domain = lib.mkOption {
type = lib.types.str;
description = ''
Primary XMPP domain. Users will have JIDs like user@domain.
'';
};
admins = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
example = [ "admin@example.org" ];
description = ''
List of admin JIDs.
'';
};
allowRegistration = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Allow in-band account registration from clients.
If false, create accounts with: prosodyctl register <user> <domain> <password>
'';
};
uploadFileSizeLimit = lib.mkOption {
type = lib.types.int;
default = 10485760;
description = ''
Maximum file upload size in bytes (default 10 MiB).
'';
};
};
};
config = lib.mkIf cfg.enable {
services.prosody = {
enable = true;
admins = cfg.admins;
allowRegistration = cfg.allowRegistration;
ssl = {
cert = "/var/lib/acme/${cfg.domain}/fullchain.pem";
key = "/var/lib/acme/${cfg.domain}/key.pem";
};
virtualHosts.${cfg.domain} = {
enabled = true;
domain = cfg.domain;
ssl = {
cert = "/var/lib/acme/${cfg.domain}/fullchain.pem";
key = "/var/lib/acme/${cfg.domain}/key.pem";
};
};
muc = [
{ domain = "conference.${cfg.domain}"; }
];
httpFileShare = {
domain = "upload.${cfg.domain}";
size_limit = cfg.uploadFileSizeLimit;
};
};
# Grant prosody read access to ACME certs (group is "nginx" since
# the nginx vhost requests the cert via enableACME)
users.users.prosody.extraGroups = [ "nginx" ];
# nginx vhost handles ACME HTTP-01 challenge for the XMPP domain.
# The cert also covers conference.* and upload.* subdomains.
services.nginx = {
enable = true;
virtualHosts.${cfg.domain} = {
enableACME = true;
forceSSL = true;
locations."/".return = "301 https://meet.${cfg.domain}";
};
};
security.acme = {
acceptTerms = true;
defaults = {
email = "hectic.yukkop.it@gmail.com";
enableDebugLogs = true;
};
# Add MUC + upload subdomains to the nginx-managed cert
certs.${cfg.domain} = {
extraDomainNames = [
"conference.${cfg.domain}"
"upload.${cfg.domain}"
];
reloadServices = [ "prosody" ];
};
};
networking.firewall = {
allowedTCPPorts = [
5222 # c2s (client-to-server)
5269 # s2s (server-to-server federation)
80 # ACME HTTP-01 challenge
443 # HTTPS
];
};
};
}

View File

@@ -40,6 +40,10 @@ in self.lib.nixpkgs-lib.nixosSystem {
"libcusparse" "libcusparse"
"cudnn" "cudnn"
]; ];
# jitsi-meet depends on libolm which is marked insecure (CVE-2024-4519x)
config.permittedInsecurePackages = [
"jitsi-meet-1.0.8792"
];
}; };
modules = [ modules = [
{ networking.hostName = name; } { networking.hostName = name; }

View File

@@ -63,6 +63,17 @@
# matrixDomain = "accord.tube"; # matrixDomain = "accord.tube";
#}; #};
hectic.services.jitsi = {
enable = true;
hostName = "meet.accord.tube";
};
hectic.services.xmpp = {
enable = true;
domain = "accord.tube";
admins = [ "yukkop@accord.tube" ];
};
networking = { networking = {
networkmanager.enable = true; networkmanager.enable = true;
useDHCP = lib.mkDefault true; useDHCP = lib.mkDefault true;
@@ -91,13 +102,13 @@
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
defaultSopsFile = ../../../sus/neuro.yaml; defaultSopsFile = ../../../sus/neuro.yaml;
secrets."init-postgresql" = {}; #secrets."init-postgresql" = {};
secrets."matrix/secrets" = {}; #secrets."matrix/secrets" = {};
secrets."matrix/turn-secret" = { #secrets."matrix/turn-secret" = {
owner = "turnserver"; # owner = "turnserver";
group = "turnserver"; # group = "turnserver";
mode = "0400"; # mode = "0400";
}; #};
}; };
boot.loader.systemd-boot.enable = true; boot.loader.systemd-boot.enable = true;