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