{ config, lib, pkgs, ... }: with lib; let cfg = config.nixfiles.modules.soju; in { options.nixfiles.modules.soju = { enable = mkEnableOption "soju"; port = mkOption { description = "Port."; type = with types; port; default = 6697; }; httpPort = mkOption { description = "HTTP Port."; type = with types; port; default = 9981; }; domain = mkOption { description = "Domain."; type = with types; str; default = config.networking.fqdn; }; uploadsDir = mkOption { description = "Uploads directory."; type = with types; str; default = "/srv/soju/uploads"; }; prometheus = { enable = mkEnableOption "Prometheus exporter" // { default = true; }; port = mkOption { description = "Port."; type = with types; port; default = 9259; }; }; }; config = let db = "soju"; in mkIf cfg.enable { nixfiles.modules = { acme.enable = true; nginx = { enable = true; upstreams.soju.servers."127.0.0.1:${toString cfg.httpPort}" = { }; virtualHosts.${cfg.domain}.locations = { "/_irc" = { proxyPass = "http://soju"; proxyWebsockets = true; extraConfig = '' rewrite ^/_irc/(.*)$ /$1 break; ''; }; "/_irc/uploads" = { root = "/srv/soju"; extraConfig = '' rewrite ^/_irc/(.*)$ /$1 break; ''; }; }; }; postgresql = { enable = true; extraPostStart = [ '' $PSQL "${db}" -tAc 'GRANT ALL ON SCHEMA "public" TO "${db}"' '' ]; }; }; services.postgresql = { ensureDatabases = [ db ]; ensureUsers = [ { name = db; ensureDBOwnership = true; } ]; }; systemd = { services.soju = { description = "soju IRC bouncer"; documentation = [ "https://soju.im/" "man:soju(1)" "man:sojuctl(1)" ]; wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" ]; requires = [ "postgresql.service" ]; after = [ "network-online.target" "postgresql.service" ]; serviceConfig = { ExecStart = let # https://soju.im/doc/soju.1.html configFile = pkgs.writeText "soju.conf" '' listen ircs://:${toString cfg.port} listen http://localhost:${toString cfg.httpPort} tls ${with config.certs.${cfg.domain}; "${directory}/fullchain.pem ${directory}/key.pem"} ${with cfg.prometheus; optionalString enable "listen http+prometheus://localhost:${toString port}"} db postgres "${ concatStringsSep " " [ "host=/run/postgresql" "user=${db}" "dbname=${db}" "sslmode=disable" ] }" message-store db file-upload fs ${cfg.uploadsDir} hostname ${cfg.domain} http-ingress https://${cfg.domain}/_irc ''; in "${pkgs.soju}/bin/soju -config ${configFile}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; DynamicUser = true; ReadWritePaths = [ cfg.uploadsDir ]; SupplementaryGroups = [ config.services.nginx.group ]; AmbientCapabilities = [ "" ]; CapabilityBoundingSet = [ "" ]; LockPersonality = true; MemoryDenyWriteExecute = true; NoNewPrivileges = true; PrivateDevices = true; PrivateTmp = true; PrivateUsers = true; ProtectClock = true; ProtectControlGroups = true; ProtectHome = true; ProtectHostname = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; ProtectSystem = "strict"; ProtectProc = "invisible"; ProcSubset = "pid"; RemoveIPC = true; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; SystemCallArchitectures = "native"; SystemCallFilter = [ "@system-service" "~@privileged" ]; }; }; tmpfiles.rules = [ "d ${cfg.uploadsDir} 0755 soju soju" ]; }; }; }