{ pkgs, lib, configVars, inputs, ... }: let containerName = "xmpp"; xmppDomain = configVars.domains.xmpp; pubKeys = lib.filesystem.listFilesRecursive ../../users/keys; hostAddress = configVars.networking.addresses.xmpp.hostAddress; externalIp = configVars.networking.addresses.cloudnix.ip; localAddress = configVars.networking.addresses.xmpp.localAddress; sops-nix = inputs.sops-nix; xmppPorts = configVars.networking.addresses.xmpp.ports; xmppUDPPorts = [ xmppPorts.coturn xmppPorts.coturn-tls ] ++ lib.range xmppPorts.coturn-min-udp xmppPorts.coturn-max-udp; xmppTCPPorts = [ xmppPorts.coturn xmppPorts.coturn-tls xmppPorts.xmpp-https xmppPorts.xmpp-http xmppPorts.xmpp-s2s xmppPorts.xmpp-c2s xmppPorts.xmpp-c2s-legacy-tls xmppPorts.xmpp-s2s-tls ]; in { networking = { nat = { enable = true; internalInterfaces = ["ve-+"]; externalInterface = "enp1s0"; }; firewall = { enable = true; allowedTCPPorts = xmppTCPPorts; allowedUDPPorts = xmppUDPPorts; }; }; imports = [ ../nginx/xmpp.nix ]; environment.persistence."/persist" = { hideMounts = true; directories = [ "/var/lib/nixos-containers/${containerName}" ]; }; systemd.tmpfiles.rules = [ "d /var/lib/prosody 0750" ]; containers."${containerName}" = { autoStart = true; privateNetwork = true; hostAddress = hostAddress; localAddress = localAddress; nixpkgs = pkgs.path; bindMounts = { "/etc/ssh/ssh_host_ed25519_key" = { hostPath = "/etc/ssh/ssh_host_ed25519_key"; isReadOnly = true; }; "/var/lib/prosody" = { hostPath = "/var/lib/prosody"; isReadOnly = false; }; "/var/lib/acme/${xmppDomain}/" = { hostPath = "/var/lib/acme/${xmppDomain}/"; isReadOnly = false; }; }; forwardPorts = lib.map (port: { protocol = "tcp"; containerPort = port; hostPort = port; }) xmppTCPPorts ++ lib.map (port: { protocol = "udp"; containerPort = port; hostPort = port; }) xmppUDPPorts; config = { pkgs, lib, config, ... }: let secretsDirectory = builtins.toString inputs.nix-secrets; secretsFile = "${secretsDirectory}/secrets.yaml"; in { users.groups.www-data = { gid = 33; }; users.users.prosody = { isSystemUser = true; uid = 149; extraGroups = ["www-data"]; }; users.users.turnserver = { isSystemUser = true; uid = 249; extraGroups = ["www-data"]; }; networking = { firewall = { enable = true; rejectPackets = true; allowedTCPPorts = xmppTCPPorts ++ [80 443]; allowedUDPPorts = xmppUDPPorts; }; useHostResolvConf = lib.mkForce false; }; services.resolved.enable = true; sops = { defaultSopsFile = "${secretsFile}"; validateSopsFiles = false; age = { sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"]; }; secrets = { "software/coturn/static-auth-secret" = { mode = "0644"; }; }; }; imports = [ sops-nix.nixosModules.sops ]; environment.systemPackages = [ pkgs.vim pkgs.git pkgs.prosody pkgs.coturn ]; sops.templates."prosody_secrets.lua" = { mode = "444"; content = '' turn_external_secret = "${config.sops.placeholder."software/coturn/static-auth-secret"}"; ''; }; services.prosody = { enable = true; package = pkgs.prosody.override { withCommunityModules = [ "turn_external" "conversejs" "admin_web" "external_services" "http_altconnect" ]; }; extraModules = [ "server_contact_info" "http_file_share" "external_services" "turn_external" "conversejs" "admin_web" "http" "websocket" "http_altconnect" ]; allowRegistration = true; extraConfig = '' Include "${config.sops.templates."prosody_secrets.lua".path}" registration_invite_only = true; allow_user_invites = true; cross_domain_bosh = true; cross_domain_websocket = true; turn_external_host = "turn.${xmppDomain}"; turn_external_port = ${toString xmppPorts.coturn}; http_default_host = "${xmppDomain}"; certificates = "certs" consider_websocket_secure = true external_services = { { port="${toString xmppPorts.coturn}"; transport="tcp"; type="stun"; host="turn.${xmppDomain}" }; { port="${toString xmppPorts.coturn}"; transport="udp"; type="turn"; host="turn.${xmppDomain}" }; } s2s_direct_tls_ports = { ${toString xmppPorts.xmpp-s2s-tls} } legacy_ssl_ports = { ${toString xmppPorts.xmpp-c2s-legacy-tls} } legacy_ssl_ssl = { certificate = "/var/lib/acme/${xmppDomain}/cert.pem"; key = "/var/lib/acme/${xmppDomain}/key.pem"; } contact_info = { admin = { "mailto:admin@${xmppDomain}", "xmpp:admin@${xmppDomain}" }; } ''; modules.bosh = true; s2sRequireEncryption = true; c2sRequireEncryption = true; s2sSecureAuth = false; admins = ["root@${xmppDomain}"]; ssl.cert = "/var/lib/acme/${xmppDomain}/fullchain.pem"; ssl.key = "/var/lib/acme/${xmppDomain}/key.pem"; httpFileShare.domain = "upload.${xmppDomain}"; virtualHosts."${xmppDomain}" = { enabled = true; ssl.cert = "/var/lib/acme/${xmppDomain}/fullchain.pem"; ssl.key = "/var/lib/acme/${xmppDomain}/key.pem"; extraConfig = '' http_external_url = "https://chat.${xmppDomain}/" invites_page = "https://chat.${xmppDomain}/register?t={invite.token}" http_paths = { invites_page = "/invite"; invites_register_web = "/register"; } disco_items = { { "upload.${xmppDomain}.com" }, { "rooms.${xmppDomain}.com" }, { "turn.${xmppDomain}.com" }, } ''; domain = "${xmppDomain}"; }; muc = [ { domain = "conference.${xmppDomain}"; } ]; uploadHttp = { domain = "https://upload.${xmppDomain}"; uploadFileSizeLimit = "1000000000"; # 1 gb file-size limit uploadExpireAfter = "31557600"; # files deleted after 1 year }; }; services.coturn = { enable = true; realm = "turn.${xmppDomain}"; use-auth-secret = true; static-auth-secret-file = config.sops.secrets."software/coturn/static-auth-secret".path; tls-listening-port = xmppPorts.coturn-tls; cert = "/var/lib/acme/${xmppDomain}/cert.pem"; pkey = "/var/lib/acme/${xmppDomain}/key.pem"; min-port = xmppPorts.coturn-min-udp; max-port = xmppPorts.coturn-max-udp; extraConfig = '' external-ip = ${externalIp}/${localAddress} log = /var/log/turnserver.log verbose ''; }; system.stateVersion = "24.05"; }; }; }