lol

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

authored by

Yaya and committed by
Yureka
f63f7810 643d213e

+376
+1
nixos/modules/module-list.nix
··· 1230 1230 ./services/web-apps/powerdns-admin.nix 1231 1231 ./services/web-apps/prosody-filer.nix 1232 1232 ./services/web-apps/restya-board.nix 1233 + ./services/web-apps/sftpgo.nix 1233 1234 ./services/web-apps/rss-bridge.nix 1234 1235 ./services/web-apps/selfoss.nix 1235 1236 ./services/web-apps/shiori.nix
+375
nixos/modules/services/web-apps/sftpgo.nix
··· 1 + { options, config, lib, pkgs, utils, ... }: 2 + 3 + with lib; 4 + 5 + let 6 + cfg = config.services.sftpgo; 7 + defaultUser = "sftpgo"; 8 + settingsFormat = pkgs.formats.json {}; 9 + configFile = settingsFormat.generate "sftpgo.json" cfg.settings; 10 + hasPrivilegedPorts = any (port: port > 0 && port < 1024) ( 11 + catAttrs "port" (cfg.settings.httpd.bindings 12 + ++ cfg.settings.ftpd.bindings 13 + ++ cfg.settings.sftpd.bindings 14 + ++ cfg.settings.webdavd.bindings 15 + ) 16 + ); 17 + in 18 + { 19 + options.services.sftpgo = { 20 + enable = mkOption { 21 + type = types.bool; 22 + default = false; 23 + description = mdDoc "sftpgo"; 24 + }; 25 + 26 + package = mkOption { 27 + type = types.package; 28 + default = pkgs.sftpgo; 29 + defaultText = literalExpression "pkgs.sftpgo"; 30 + description = mdDoc '' 31 + Which SFTPGo package to use. 32 + ''; 33 + }; 34 + 35 + extraArgs = mkOption { 36 + type = with types; listOf str; 37 + default = []; 38 + description = mdDoc '' 39 + Additional command line arguments to pass to the sftpgo daemon. 40 + ''; 41 + example = [ "--log-level" "info" ]; 42 + }; 43 + 44 + dataDir = mkOption { 45 + type = types.str; 46 + default = "/var/lib/sftpgo"; 47 + description = mdDoc '' 48 + The directory where SFTPGo stores its data files. 49 + ''; 50 + }; 51 + 52 + user = mkOption { 53 + type = types.str; 54 + default = defaultUser; 55 + description = mdDoc '' 56 + User account name under which SFTPGo runs. 57 + ''; 58 + }; 59 + 60 + group = mkOption { 61 + type = types.str; 62 + default = defaultUser; 63 + description = mdDoc '' 64 + Group name under which SFTPGo runs. 65 + ''; 66 + }; 67 + 68 + loadDataFile = mkOption { 69 + default = null; 70 + type = with types; nullOr path; 71 + description = mdDoc '' 72 + Path to a json file containing users and folders to load (or update) on startup. 73 + Check the [documentation](https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md) 74 + for the `--loaddata-from` command line argument for more info. 75 + ''; 76 + }; 77 + 78 + settings = mkOption { 79 + default = {}; 80 + description = mdDoc '' 81 + The primary sftpgo configuration. See the 82 + [configuration reference](https://github.com/drakkan/sftpgo/blob/main/docs/full-configuration.md) 83 + for possible values. 84 + ''; 85 + type = with types; submodule { 86 + freeformType = settingsFormat.type; 87 + options = { 88 + httpd.bindings = mkOption { 89 + default = []; 90 + description = mdDoc '' 91 + Configure listen addresses and ports for httpd. 92 + ''; 93 + type = types.listOf (types.submodule { 94 + freeformType = settingsFormat.type; 95 + options = { 96 + address = mkOption { 97 + type = types.str; 98 + default = "127.0.0.1"; 99 + description = mdDoc '' 100 + Network listen address. Leave blank to listen on all available network interfaces. 101 + On *NIX you can specify an absolute path to listen on a Unix-domain socket. 102 + ''; 103 + }; 104 + 105 + port = mkOption { 106 + type = types.port; 107 + default = 8080; 108 + description = mdDoc '' 109 + The port for serving HTTP(S) requests. 110 + 111 + Setting the port to `0` disables listening on this interface binding. 112 + ''; 113 + }; 114 + 115 + enable_web_admin = mkOption { 116 + type = types.bool; 117 + default = true; 118 + description = mdDoc '' 119 + Enable the built-in web admin for this interface binding. 120 + ''; 121 + }; 122 + 123 + enable_web_client = mkOption { 124 + type = types.bool; 125 + default = true; 126 + description = mdDoc '' 127 + Enable the built-in web client for this interface binding. 128 + ''; 129 + }; 130 + }; 131 + }); 132 + }; 133 + 134 + ftpd.bindings = mkOption { 135 + default = []; 136 + description = mdDoc '' 137 + Configure listen addresses and ports for ftpd. 138 + ''; 139 + type = types.listOf (types.submodule { 140 + freeformType = settingsFormat.type; 141 + options = { 142 + address = mkOption { 143 + type = types.str; 144 + default = "127.0.0.1"; 145 + description = mdDoc '' 146 + Network listen address. Leave blank to listen on all available network interfaces. 147 + On *NIX you can specify an absolute path to listen on a Unix-domain socket. 148 + ''; 149 + }; 150 + 151 + port = mkOption { 152 + type = types.port; 153 + default = 0; 154 + description = mdDoc '' 155 + The port for serving FTP requests. 156 + 157 + Setting the port to `0` disables listening on this interface binding. 158 + ''; 159 + }; 160 + }; 161 + }); 162 + }; 163 + 164 + sftpd.bindings = mkOption { 165 + default = []; 166 + description = mdDoc '' 167 + Configure listen addresses and ports for sftpd. 168 + ''; 169 + type = types.listOf (types.submodule { 170 + freeformType = settingsFormat.type; 171 + options = { 172 + address = mkOption { 173 + type = types.str; 174 + default = "127.0.0.1"; 175 + description = mdDoc '' 176 + Network listen address. Leave blank to listen on all available network interfaces. 177 + On *NIX you can specify an absolute path to listen on a Unix-domain socket. 178 + ''; 179 + }; 180 + 181 + port = mkOption { 182 + type = types.port; 183 + default = 0; 184 + description = mdDoc '' 185 + The port for serving SFTP requests. 186 + 187 + Setting the port to `0` disables listening on this interface binding. 188 + ''; 189 + }; 190 + }; 191 + }); 192 + }; 193 + 194 + webdavd.bindings = mkOption { 195 + default = []; 196 + description = mdDoc '' 197 + Configure listen addresses and ports for webdavd. 198 + ''; 199 + type = types.listOf (types.submodule { 200 + freeformType = settingsFormat.type; 201 + options = { 202 + address = mkOption { 203 + type = types.str; 204 + default = "127.0.0.1"; 205 + description = mdDoc '' 206 + Network listen address. Leave blank to listen on all available network interfaces. 207 + On *NIX you can specify an absolute path to listen on a Unix-domain socket. 208 + ''; 209 + }; 210 + 211 + port = mkOption { 212 + type = types.port; 213 + default = 0; 214 + description = mdDoc '' 215 + The port for serving WebDAV requests. 216 + 217 + Setting the port to `0` disables listening on this interface binding. 218 + ''; 219 + }; 220 + }; 221 + }); 222 + }; 223 + 224 + smtp = mkOption { 225 + default = {}; 226 + description = mdDoc '' 227 + SMTP configuration section. 228 + ''; 229 + type = types.submodule { 230 + freeformType = settingsFormat.type; 231 + options = { 232 + host = mkOption { 233 + type = types.str; 234 + default = ""; 235 + description = mdDoc '' 236 + Location of SMTP email server. Leave empty to disable email sending capabilities. 237 + ''; 238 + }; 239 + 240 + port = mkOption { 241 + type = types.port; 242 + default = 465; 243 + description = mdDoc "Port of the SMTP Server."; 244 + }; 245 + 246 + encryption = mkOption { 247 + type = types.enum [ 0 1 2 ]; 248 + default = 1; 249 + description = mdDoc '' 250 + Encryption scheme: 251 + - `0`: No encryption 252 + - `1`: TLS 253 + - `2`: STARTTLS 254 + ''; 255 + }; 256 + 257 + auth_type = mkOption { 258 + type = types.enum [ 0 1 2 ]; 259 + default = 0; 260 + description = mdDoc '' 261 + - `0`: Plain 262 + - `1`: Login 263 + - `2`: CRAM-MD5 264 + ''; 265 + }; 266 + 267 + user = mkOption { 268 + type = types.str; 269 + default = "sftpgo"; 270 + description = mdDoc "SMTP username."; 271 + }; 272 + 273 + from = mkOption { 274 + type = types.str; 275 + default = "SFTPGo <sftpgo@example.com>"; 276 + description = mdDoc '' 277 + From address. 278 + ''; 279 + }; 280 + }; 281 + }; 282 + }; 283 + }; 284 + }; 285 + }; 286 + }; 287 + 288 + config = mkIf cfg.enable { 289 + services.sftpgo.settings = (mapAttrs (name: mkDefault) { 290 + ftpd.bindings = [{ port = 0; }]; 291 + httpd.bindings = [{ port = 0; }]; 292 + sftpd.bindings = [{ port = 0; }]; 293 + webdavd.bindings = [{ port = 0; }]; 294 + httpd.openapi_path = "${cfg.package}/share/sftpgo/openapi"; 295 + httpd.templates_path = "${cfg.package}/share/sftpgo/templates"; 296 + httpd.static_files_path = "${cfg.package}/share/sftpgo/static"; 297 + smtp.templates_path = "${cfg.package}/share/sftpgo/templates"; 298 + }); 299 + 300 + users = optionalAttrs (cfg.user == defaultUser) { 301 + users = { 302 + ${defaultUser} = { 303 + description = "SFTPGo system user"; 304 + isSystemUser = true; 305 + group = defaultUser; 306 + home = cfg.dataDir; 307 + }; 308 + }; 309 + 310 + groups = { 311 + ${defaultUser} = { 312 + members = [ defaultUser ]; 313 + }; 314 + }; 315 + }; 316 + 317 + systemd.services.sftpgo = { 318 + description = "SFTPGo daemon"; 319 + after = [ "network.target" ]; 320 + wantedBy = [ "multi-user.target" ]; 321 + 322 + environment = { 323 + SFTPGO_CONFIG_FILE = mkDefault configFile; 324 + SFTPGO_LOG_FILE_PATH = mkDefault ""; # log to journal 325 + SFTPGO_LOADDATA_FROM = mkIf (cfg.loadDataFile != null) cfg.loadDataFile; 326 + }; 327 + 328 + serviceConfig = mkMerge [ 329 + ({ 330 + Type = "simple"; 331 + User = cfg.user; 332 + Group = cfg.group; 333 + WorkingDirectory = cfg.dataDir; 334 + ReadWritePaths = [ cfg.dataDir ]; 335 + LimitNOFILE = 8192; # taken from upstream 336 + KillMode = "mixed"; 337 + ExecStart = "${cfg.package}/bin/sftpgo serve ${utils.escapeSystemdExecArgs cfg.extraArgs}"; 338 + ExecReload = "${pkgs.util-linux}/bin/kill -s HUP $MAINPID"; 339 + 340 + # Service hardening 341 + CapabilityBoundingSet = [ (optionalString hasPrivilegedPorts "CAP_NET_BIND_SERVICE") ]; 342 + DevicePolicy = "closed"; 343 + LockPersonality = true; 344 + NoNewPrivileges = true; 345 + PrivateDevices = true; 346 + PrivateTmp = true; 347 + ProcSubset = "pid"; 348 + ProtectClock = true; 349 + ProtectControlGroups = true; 350 + ProtectHome = true; 351 + ProtectHostname = true; 352 + ProtectKernelLogs = true; 353 + ProtectKernelModules = true; 354 + ProtectKernelTunables = true; 355 + ProtectProc = "invisible"; 356 + ProtectSystem = "strict"; 357 + RemoveIPC = true; 358 + RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX"; 359 + RestrictNamespaces = true; 360 + RestrictRealtime = true; 361 + RestrictSUIDSGID = true; 362 + SystemCallArchitectures = "native"; 363 + SystemCallFilter = [ "@system-service" "~@privileged" ]; 364 + UMask = "0077"; 365 + }) 366 + (mkIf hasPrivilegedPorts { 367 + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; 368 + }) 369 + (mkIf (cfg.dataDir == options.services.sftpgo.dataDir.default) { 370 + StateDirectory = baseNameOf cfg.dataDir; 371 + }) 372 + ]; 373 + }; 374 + }; 375 + }