grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / web-apps / filesender.nix
blobbc8d465643f2ffd2f34596c843c665244dfac51a
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
8   format = pkgs.formats.php { finalVariable = "config"; };
10   cfg = config.services.filesender;
11   simpleSamlCfg = config.services.simplesamlphp.filesender;
12   fpm = config.services.phpfpm.pools.filesender;
14   filesenderConfigDirectory = pkgs.runCommand "filesender-config" { } ''
15     mkdir $out
16     cp ${format.generate "config.php" cfg.settings} $out/config.php
17   '';
20   meta = {
21     maintainers = with lib.maintainers; [ nhnn ];
22     doc = ./filesender.md;
23   };
25   options.services.filesender = with lib; {
26     enable = mkEnableOption "FileSender";
27     package = mkPackageOption pkgs "filesender" { };
28     user = mkOption {
29       description = "User under which filesender runs.";
30       type = types.str;
31       default = "filesender";
32     };
33     database = {
34       createLocally = mkOption {
35         type = types.bool;
36         default = true;
37         description = ''
38           Create the PostgreSQL database and database user locally.
39         '';
40       };
41       hostname = mkOption {
42         type = types.str;
43         default = "/run/postgresql";
44         description = "Database hostname.";
45       };
46       port = mkOption {
47         type = types.port;
48         default = 5432;
49         description = "Database port.";
50       };
51       name = mkOption {
52         type = types.str;
53         default = "filesender";
54         description = "Database name.";
55       };
56       user = mkOption {
57         type = types.str;
58         default = "filesender";
59         description = "Database user.";
60       };
61       passwordFile = mkOption {
62         type = types.nullOr types.path;
63         default = null;
64         example = "/run/keys/filesender-dbpassword";
65         description = ''
66           A file containing the password corresponding to
67           [](#opt-services.filesender.database.user).
68         '';
69       };
70     };
71     settings = mkOption {
72       type = types.submodule {
73         freeformType = format.type;
74         options = {
75           site_url = mkOption {
76             type = types.str;
77             description = "Site URL. Used in emails, to build URLs for logging in, logging out, build URL for upload endpoint for web workers, to include scripts etc.";
78           };
79           admin = mkOption {
80             type = types.commas;
81             description = ''
82               UIDs (as per the configured saml_uid_attribute) of FileSender administrators.
83               Accounts with these UIDs can access the Admin page through the web UI.
84             '';
85           };
86           admin_email = mkOption {
87             type = types.commas;
88             description = ''
89               Email address of FileSender administrator(s).
90               Emails regarding disk full etc. are sent here.
91               You should use a role-address here.
92             '';
93           };
94           storage_filesystem_path = mkOption {
95             type = types.nullOr types.str;
96             description = "When using storage type filesystem this is the absolute path to the file system where uploaded files are stored until they expire. Your FileSender storage root.";
97           };
98           log_facilities = mkOption {
99             type = format.type;
100             default = [ { type = "error_log"; } ];
101             description = "Defines where FileSender logging is sent. You can sent logging to a file, to syslog or to the default PHP log facility (as configured through your webserver's PHP module). The directive takes an array of one or more logging targets. Logging can be sent to multiple targets simultaneously. Each logging target is a list containing the name of the logging target and a number of attributes which vary per log target. See below for the exact definiation of each log target.";
102           };
103         };
104       };
105       default = { };
106       description = ''
107         Configuration options used by FileSender.
108         See [](https://docs.filesender.org/filesender/v2.0/admin/configuration/)
109         for available options.
110       '';
111     };
112     configureNginx = mkOption {
113       type = types.bool;
114       default = true;
115       description = "Configure nginx as a reverse proxy for FileSender.";
116     };
117     localDomain = mkOption {
118       type = types.str;
119       example = "filesender.example.org";
120       description = "The domain serving your FileSender instance.";
121     };
122     poolSettings = mkOption {
123       type =
124         with types;
125         attrsOf (oneOf [
126           str
127           int
128           bool
129         ]);
130       default = {
131         "pm" = "dynamic";
132         "pm.max_children" = "32";
133         "pm.start_servers" = "2";
134         "pm.min_spare_servers" = "2";
135         "pm.max_spare_servers" = "4";
136         "pm.max_requests" = "500";
137       };
138       description = ''
139         Options for FileSender's PHP pool. See the documentation on `php-fpm.conf` for details on configuration directives.
140       '';
141     };
142   };
143   config = lib.mkIf cfg.enable {
144     services.simplesamlphp.filesender = {
145       phpfpmPool = "filesender";
146       localDomain = cfg.localDomain;
147       settings.baseurlpath = lib.mkDefault "https://${cfg.localDomain}/saml";
148     };
150     services.phpfpm = {
151       pools.filesender = {
152         user = cfg.user;
153         group = config.services.nginx.group;
154         phpEnv = {
155           FILESENDER_CONFIG_DIR = toString filesenderConfigDirectory;
156           SIMPLESAMLPHP_CONFIG_DIR = toString simpleSamlCfg.configDir;
157         };
158         settings = {
159           "listen.owner" = config.services.nginx.user;
160           "listen.group" = config.services.nginx.group;
161         } // cfg.poolSettings;
162       };
163     };
165     services.nginx = lib.mkIf cfg.configureNginx {
166       enable = true;
167       virtualHosts.${cfg.localDomain} = {
168         root = "${cfg.package}/www";
169         extraConfig = ''
170           index index.php;
171         '';
172         locations = {
173           "/".extraConfig = ''
174             try_files $uri $uri/ /index.php?args;
175           '';
176           "~ [^/]\\.php(/|$)" = {
177             extraConfig = ''
178               fastcgi_split_path_info  ^(.+\.php)(/.+)$;
179               fastcgi_pass  unix:${fpm.socket};
180               include ${pkgs.nginx}/conf/fastcgi.conf;
181               fastcgi_intercept_errors on;
182               fastcgi_param PATH_INFO       $fastcgi_path_info;
183               fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
184             '';
185           };
186           "~ /\\.".extraConfig = "deny all;";
187         };
188       };
189     };
191     services.postgresql = lib.mkIf cfg.database.createLocally {
192       enable = true;
193       ensureDatabases = [ cfg.database.name ];
194       ensureUsers = [
195         {
196           name = cfg.database.user;
197           ensureDBOwnership = true;
198         }
199       ];
200     };
202     services.filesender.settings = lib.mkMerge [
203       (lib.mkIf cfg.database.createLocally {
204         db_host = "/run/postgresql";
205         db_port = "5432";
206         db_password = "."; # FileSender requires it even when on UNIX socket auth.
207       })
208       (lib.mkIf (!cfg.database.createLocally) {
209         db_host = cfg.database.hostname;
210         db_port = toString cfg.database.port;
211         db_password = format.lib.mkRaw "file_get_contents('${cfg.database.passwordFile}')";
212       })
213       {
214         site_url = lib.mkDefault "https://${cfg.localDomain}";
215         db_type = "pgsql";
216         db_username = cfg.database.user;
217         db_database = cfg.database.name;
218         "auth_sp_saml_simplesamlphp_url" = "/saml";
219         "auth_sp_saml_simplesamlphp_location" = "${simpleSamlCfg.libDir}";
220       }
221     ];
223     systemd.services.filesender-initdb = {
224       description = "Init filesender DB";
226       wantedBy = [
227         "multi-user.target"
228         "phpfpm-filesender.service"
229       ];
230       after = [ "postgresql.service" ];
232       restartIfChanged = true;
234       serviceConfig = {
235         Environment = [
236           "FILESENDER_CONFIG_DIR=${toString filesenderConfigDirectory}"
237           "SIMPLESAMLPHP_CONFIG_DIR=${toString simpleSamlCfg.configDir}"
238         ];
239         Type = "oneshot";
240         Group = config.services.nginx.group;
241         User = "filesender";
242         ExecStart = "${fpm.phpPackage}/bin/php ${cfg.package}/scripts/upgrade/database.php";
243       };
244     };
246     users.extraUsers.filesender = lib.mkIf (cfg.user == "filesender") {
247       home = "/var/lib/filesender";
248       group = config.services.nginx.group;
249       createHome = true;
250       isSystemUser = true;
251     };
252   };