summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYaya <mak@nyantec.com>2023-04-19 13:13:47 +0000
committerYaya <mak@nyantec.com>2023-05-30 12:31:40 +0000
commitb092d789335cc042e5dd4e71c5ff566f30bb1ebb (patch)
tree983745cd660ba895c32005dc16c29bad7351d3ea
parentsftpgo: add yayayayaka to maintainers (diff)
downloadnixpkgs-b092d789335cc042e5dd4e71c5ff566f30bb1ebb.tar.gz
nixos/sftpgo: init
A fully featured and highly configurable SFTP server with optional HTTP/S, FTP/S and WebDAV support. https://github.com/drakkan/sftpgo (cherry picked from commit a11c9cf7dc744c485022ef4784f0899b5eb10987)
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/web-apps/sftpgo.nix375
2 files changed, 376 insertions, 0 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index ff06a72ff9dd..87eb813455d9 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -1230,6 +1230,7 @@
./services/web-apps/powerdns-admin.nix
./services/web-apps/prosody-filer.nix
./services/web-apps/restya-board.nix
+ ./services/web-apps/sftpgo.nix
./services/web-apps/rss-bridge.nix
./services/web-apps/selfoss.nix
./services/web-apps/shiori.nix
diff --git a/nixos/modules/services/web-apps/sftpgo.nix b/nixos/modules/services/web-apps/sftpgo.nix
new file mode 100644
index 000000000000..846478ecbd6d
--- /dev/null
+++ b/nixos/modules/services/web-apps/sftpgo.nix
@@ -0,0 +1,375 @@
+{ options, config, lib, pkgs, utils, ... }:
+
+with lib;
+
+let
+ cfg = config.services.sftpgo;
+ defaultUser = "sftpgo";
+ settingsFormat = pkgs.formats.json {};
+ configFile = settingsFormat.generate "sftpgo.json" cfg.settings;
+ hasPrivilegedPorts = any (port: port > 0 && port < 1024) (
+ catAttrs "port" (cfg.settings.httpd.bindings
+ ++ cfg.settings.ftpd.bindings
+ ++ cfg.settings.sftpd.bindings
+ ++ cfg.settings.webdavd.bindings
+ )
+ );
+in
+{
+ options.services.sftpgo = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = mdDoc "sftpgo";
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.sftpgo;
+ defaultText = literalExpression "pkgs.sftpgo";
+ description = mdDoc ''
+ Which SFTPGo package to use.
+ '';
+ };
+
+ extraArgs = mkOption {
+ type = with types; listOf str;
+ default = [];
+ description = mdDoc ''
+ Additional command line arguments to pass to the sftpgo daemon.
+ '';
+ example = [ "--log-level" "info" ];
+ };
+
+ dataDir = mkOption {
+ type = types.str;
+ default = "/var/lib/sftpgo";
+ description = mdDoc ''
+ The directory where SFTPGo stores its data files.
+ '';
+ };
+
+ user = mkOption {
+ type = types.str;
+ default = defaultUser;
+ description = mdDoc ''
+ User account name under which SFTPGo runs.
+ '';
+ };
+
+ group = mkOption {
+ type = types.str;
+ default = defaultUser;
+ description = mdDoc ''
+ Group name under which SFTPGo runs.
+ '';
+ };
+
+ loadDataFile = mkOption {
+ default = null;
+ type = with types; nullOr path;
+ description = mdDoc ''
+ Path to a json file containing users and folders to load (or update) on startup.
+ Check the [documentation](https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md)
+ for the `--loaddata-from` command line argument for more info.
+ '';
+ };
+
+ settings = mkOption {
+ default = {};
+ description = mdDoc ''
+ The primary sftpgo configuration. See the
+ [configuration reference](https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md)
+ for possible values.
+ '';
+ type = with types; submodule {
+ freeformType = settingsFormat.type;
+ options = {
+ httpd.bindings = mkOption {
+ default = [];
+ description = mdDoc ''
+ Configure listen addresses and ports for httpd.
+ '';
+ type = types.listOf (types.submodule {
+ freeformType = settingsFormat.type;
+ options = {
+ address = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ description = mdDoc ''
+ Network listen address. Leave blank to listen on all available network interfaces.
+ On *NIX you can specify an absolute path to listen on a Unix-domain socket.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 8080;
+ description = mdDoc ''
+ The port for serving HTTP(S) requests.
+
+ Setting the port to `0` disables listening on this interface binding.
+ '';
+ };
+
+ enable_web_admin = mkOption {
+ type = types.bool;
+ default = true;
+ description = mdDoc ''
+ Enable the built-in web admin for this interface binding.
+ '';
+ };
+
+ enable_web_client = mkOption {
+ type = types.bool;
+ default = true;
+ description = mdDoc ''
+ Enable the built-in web client for this interface binding.
+ '';
+ };
+ };
+ });
+ };
+
+ ftpd.bindings = mkOption {
+ default = [];
+ description = mdDoc ''
+ Configure listen addresses and ports for ftpd.
+ '';
+ type = types.listOf (types.submodule {
+ freeformType = settingsFormat.type;
+ options = {
+ address = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ description = mdDoc ''
+ Network listen address. Leave blank to listen on all available network interfaces.
+ On *NIX you can specify an absolute path to listen on a Unix-domain socket.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 0;
+ description = mdDoc ''
+ The port for serving FTP requests.
+
+ Setting the port to `0` disables listening on this interface binding.
+ '';
+ };
+ };
+ });
+ };
+
+ sftpd.bindings = mkOption {
+ default = [];
+ description = mdDoc ''
+ Configure listen addresses and ports for sftpd.
+ '';
+ type = types.listOf (types.submodule {
+ freeformType = settingsFormat.type;
+ options = {
+ address = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ description = mdDoc ''
+ Network listen address. Leave blank to listen on all available network interfaces.
+ On *NIX you can specify an absolute path to listen on a Unix-domain socket.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 0;
+ description = mdDoc ''
+ The port for serving SFTP requests.
+
+ Setting the port to `0` disables listening on this interface binding.
+ '';
+ };
+ };
+ });
+ };
+
+ webdavd.bindings = mkOption {
+ default = [];
+ description = mdDoc ''
+ Configure listen addresses and ports for webdavd.
+ '';
+ type = types.listOf (types.submodule {
+ freeformType = settingsFormat.type;
+ options = {
+ address = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ description = mdDoc ''
+ Network listen address. Leave blank to listen on all available network interfaces.
+ On *NIX you can specify an absolute path to listen on a Unix-domain socket.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 0;
+ description = mdDoc ''
+ The port for serving WebDAV requests.
+
+ Setting the port to `0` disables listening on this interface binding.
+ '';
+ };
+ };
+ });
+ };
+
+ smtp = mkOption {
+ default = {};
+ description = mdDoc ''
+ SMTP configuration section.
+ '';
+ type = types.submodule {
+ freeformType = settingsFormat.type;
+ options = {
+ host = mkOption {
+ type = types.str;
+ default = "";
+ description = mdDoc ''
+ Location of SMTP email server. Leave empty to disable email sending capabilities.
+ '';
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 465;
+ description = mdDoc "Port of the SMTP Server.";
+ };
+
+ encryption = mkOption {
+ type = types.enum [ 0 1 2 ];
+ default = 1;
+ description = mdDoc ''
+ Encryption scheme:
+ - `0`: No encryption
+ - `1`: TLS
+ - `2`: STARTTLS
+ '';
+ };
+
+ auth_type = mkOption {
+ type = types.enum [ 0 1 2 ];
+ default = 0;
+ description = mdDoc ''
+ - `0`: Plain
+ - `1`: Login
+ - `2`: CRAM-MD5
+ '';
+ };
+
+ user = mkOption {
+ type = types.str;
+ default = "sftpgo";
+ description = mdDoc "SMTP username.";
+ };
+
+ from = mkOption {
+ type = types.str;
+ default = "SFTPGo <sftpgo@example.com>";
+ description = mdDoc ''
+ From address.
+ '';
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services.sftpgo.settings = (mapAttrs (name: mkDefault) {
+ ftpd.bindings = [{ port = 0; }];
+ httpd.bindings = [{ port = 0; }];
+ sftpd.bindings = [{ port = 0; }];
+ webdavd.bindings = [{ port = 0; }];
+ httpd.openapi_path = "${cfg.package}/share/sftpgo/openapi";
+ httpd.templates_path = "${cfg.package}/share/sftpgo/templates";
+ httpd.static_files_path = "${cfg.package}/share/sftpgo/static";
+ smtp.templates_path = "${cfg.package}/share/sftpgo/templates";
+ });
+
+ users = optionalAttrs (cfg.user == defaultUser) {
+ users = {
+ ${defaultUser} = {
+ description = "SFTPGo system user";
+ isSystemUser = true;
+ group = defaultUser;
+ home = cfg.dataDir;
+ };
+ };
+
+ groups = {
+ ${defaultUser} = {
+ members = [ defaultUser ];
+ };
+ };
+ };
+
+ systemd.services.sftpgo = {
+ description = "SFTPGo daemon";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+
+ environment = {
+ SFTPGO_CONFIG_FILE = mkDefault configFile;
+ SFTPGO_LOG_FILE_PATH = mkDefault ""; # log to journal
+ SFTPGO_LOADDATA_FROM = mkIf (cfg.loadDataFile != null) cfg.loadDataFile;
+ };
+
+ serviceConfig = mkMerge [
+ ({
+ Type = "simple";
+ User = cfg.user;
+ Group = cfg.group;
+ WorkingDirectory = cfg.dataDir;
+ ReadWritePaths = [ cfg.dataDir ];
+ LimitNOFILE = 8192; # taken from upstream
+ KillMode = "mixed";
+ ExecStart = "${cfg.package}/bin/sftpgo serve ${utils.escapeSystemdExecArgs cfg.extraArgs}";
+ ExecReload = "${pkgs.util-linux}/bin/kill -s HUP $MAINPID";
+
+ # Service hardening
+ CapabilityBoundingSet = [ (optionalString hasPrivilegedPorts "CAP_NET_BIND_SERVICE") ];
+ DevicePolicy = "closed";
+ LockPersonality = true;
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateTmp = true;
+ ProcSubset = "pid";
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectProc = "invisible";
+ ProtectSystem = "strict";
+ RemoveIPC = true;
+ RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX";
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = [ "@system-service" "~@privileged" ];
+ UMask = "0077";
+ })
+ (mkIf hasPrivilegedPorts {
+ AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+ })
+ (mkIf (cfg.dataDir == options.services.sftpgo.dataDir.default) {
+ StateDirectory = baseNameOf cfg.dataDir;
+ })
+ ];
+ };
+ };
+}