about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/services/web-apps/slskd.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services/web-apps/slskd.nix')
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/slskd.nix211
1 files changed, 211 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/web-apps/slskd.nix b/nixpkgs/nixos/modules/services/web-apps/slskd.nix
new file mode 100644
index 000000000000..33353a59440c
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/slskd.nix
@@ -0,0 +1,211 @@
+{ lib, pkgs, config, ... }:
+
+let
+  settingsFormat = pkgs.formats.yaml {};
+in {
+  options.services.slskd = with lib; with types; {
+    enable = mkEnableOption "enable slskd";
+
+    rotateLogs = mkEnableOption "enable an unit and timer that will rotate logs in /var/slskd/logs";
+
+    package = mkPackageOptionMD pkgs "slskd" { };
+
+    nginx = mkOption {
+      description = lib.mdDoc "options for nginx";
+      example = {
+        enable = true;
+        domain = "example.com";
+        contextPath = "/slskd";
+      };
+      type = submodule ({name, config, ...}: {
+        options = {
+          enable = mkEnableOption "enable nginx as a reverse proxy";
+
+          domainName = mkOption {
+            type = str;
+            description = "Domain you want to use";
+          };
+          contextPath = mkOption {
+            type = types.path;
+            default = "/";
+            description = lib.mdDoc ''
+              The context path, i.e., the last part of the slskd
+              URL. Typically '/' or '/slskd'. Default '/'
+            '';
+          };
+        };
+      });
+    };
+
+    environmentFile = mkOption {
+      type = path;
+      description = ''
+        Path to a file containing secrets.
+        It must at least contain the variable `SLSKD_SLSK_PASSWORD`
+      '';
+    };
+
+    openFirewall = mkOption {
+      type = bool;
+      description = ''
+        Whether to open the firewall for services.slskd.settings.listen_port";
+      '';
+      default = false;
+    };
+
+    settings = mkOption {
+      description = lib.mdDoc ''
+        Configuration for slskd, see
+        [available options](https://github.com/slskd/slskd/blob/master/docs/config.md)
+        `APP_DIR` is set to /var/lib/slskd, where default download & incomplete directories,
+        log and databases will be created.
+      '';
+      default = {};
+      type = submodule {
+        freeformType = settingsFormat.type;
+        options = {
+
+          soulseek = {
+            username = mkOption {
+              type = str;
+              description = "Username on the Soulseek Network";
+            };
+            listen_port = mkOption {
+              type = port;
+              description = "Port to use for communication on the Soulseek Network";
+              default = 50000;
+            };
+          };
+
+          web = {
+            port = mkOption {
+              type = port;
+              default = 5001;
+              description = "The HTTP listen port";
+            };
+            url_base = mkOption {
+              type = path;
+              default = config.services.slskd.nginx.contextPath;
+              defaultText = "config.services.slskd.nginx.contextPath";
+              description = lib.mdDoc ''
+                The context path, i.e., the last part of the slskd URL
+              '';
+            };
+          };
+
+          shares = {
+            directories = mkOption {
+              type = listOf str;
+              description = lib.mdDoc ''
+                Paths to your shared directories. See
+                [documentation](https://github.com/slskd/slskd/blob/master/docs/config.md#directories)
+                for advanced usage
+              '';
+            };
+          };
+
+          directories = {
+            incomplete = mkOption {
+              type = nullOr path;
+              description = "Directory where downloading files are stored";
+              defaultText = "<APP_DIR>/incomplete";
+              default = null;
+            };
+            downloads = mkOption {
+              type = nullOr path;
+              description = "Directory where downloaded files are stored";
+              defaultText = "<APP_DIR>/downloads";
+              default = null;
+            };
+          };
+        };
+      };
+    };
+  };
+
+  config = let
+    cfg = config.services.slskd;
+
+    confWithoutNullValues = (lib.filterAttrs (key: value: value != null) cfg.settings);
+
+    configurationYaml = settingsFormat.generate "slskd.yml" confWithoutNullValues;
+
+  in lib.mkIf cfg.enable {
+
+    users = {
+      users.slskd = {
+        isSystemUser = true;
+        group = "slskd";
+      };
+      groups.slskd = {};
+    };
+
+    # Reverse proxy configuration
+    services.nginx.enable = true;
+    services.nginx.virtualHosts."${cfg.nginx.domainName}" = {
+      forceSSL = true;
+      enableACME = true;
+      locations = {
+        "${cfg.nginx.contextPath}" = {
+          proxyPass = "http://localhost:${toString cfg.settings.web.port}";
+          proxyWebsockets = true;
+        };
+      };
+    };
+
+    # Hide state & logs
+    systemd.tmpfiles.rules = [
+      "d /var/lib/slskd/data 0750 slskd slskd - -"
+      "d /var/lib/slskd/logs 0750 slskd slskd - -"
+    ];
+
+    systemd.services.slskd = {
+      description = "A modern client-server application for the Soulseek file sharing network";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "simple";
+        User = "slskd";
+        EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
+        StateDirectory = "slskd";
+        ExecStart = "${cfg.package}/bin/slskd --app-dir /var/lib/slskd --config ${configurationYaml}";
+        Restart = "on-failure";
+        ReadOnlyPaths = map (d: builtins.elemAt (builtins.split "[^/]*(/.+)" d) 1) cfg.settings.shares.directories;
+        LockPersonality = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = true;
+        PrivateTmp = true;
+        PrivateUsers = true;
+        ProtectClock = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectHostname = true;
+        ProtectKernelLogs = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        ProtectProc = "invisible";
+        ProtectSystem = "strict";
+        RemoveIPC = true;
+        RestrictNamespaces = true;
+        RestrictSUIDSGID = true;
+      };
+    };
+
+    networking.firewall.allowedTCPPorts = lib.optional cfg.openFirewall cfg.settings.soulseek.listen_port;
+
+    systemd.services.slskd-rotatelogs = lib.mkIf cfg.rotateLogs {
+      description = "Rotate slskd logs";
+      serviceConfig = {
+        Type = "oneshot";
+        User = "slskd";
+        ExecStart = [
+          "${pkgs.findutils}/bin/find /var/lib/slskd/logs/ -type f -mtime +10 -delete"
+          "${pkgs.findutils}/bin/find /var/lib/slskd/logs/ -type f -mtime +1  -exec ${pkgs.gzip}/bin/gzip -q {} ';'"
+        ];
+      };
+      startAt = "daily";
+    };
+
+  };
+}