diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index f7e4ee6cd1e..6734929b9d4 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -820,6 +820,7 @@
./services/web-apps/icingaweb2/icingaweb2.nix
./services/web-apps/icingaweb2/module-monitoring.nix
./services/web-apps/ihatemoney
+ ./services/web-apps/jirafeau.nix
./services/web-apps/limesurvey.nix
./services/web-apps/mattermost.nix
./services/web-apps/mediawiki.nix
diff --git a/nixos/modules/services/web-apps/jirafeau.nix b/nixos/modules/services/web-apps/jirafeau.nix
new file mode 100644
index 00000000000..4f181257ef7
--- /dev/null
+++ b/nixos/modules/services/web-apps/jirafeau.nix
@@ -0,0 +1,169 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.services.jirafeau;
+
+ group = config.services.nginx.group;
+ user = config.services.nginx.user;
+
+ withTrailingSlash = str: if hasSuffix "/" str then str else "${str}/";
+
+ localConfig = pkgs.writeText "config.local.php" ''
+ for supported
+ values.
+ '';
+ };
+
+ hostName = mkOption {
+ type = types.str;
+ default = "localhost";
+ description = "URL of instance. Must have trailing slash.";
+ };
+
+ maxUploadSizeMegabytes = mkOption {
+ type = types.int;
+ default = 0;
+ description = "Maximum upload size of accepted files.";
+ };
+
+ maxUploadTimeout = mkOption {
+ type = types.str;
+ default = "30m";
+ description = let
+ nginxCoreDocumentation = "http://nginx.org/en/docs/http/ngx_http_core_module.html";
+ in
+ ''
+ Timeout for reading client request bodies and headers. Refer to
+ and
+ for accepted values.
+ '';
+ };
+
+ nginxConfig = mkOption {
+ type = types.submodule
+ (import ../web-servers/nginx/vhost-options.nix { inherit config lib; });
+ default = {};
+ example = {
+ serverAliases = [ "wiki.\${config.networking.domain}" ];
+ };
+ description = "Extra configuration for the nginx virtual host of Jirafeau.";
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.jirafeau;
+ defaultText = "pkgs.jirafeau";
+ description = "Jirafeau package to use";
+ example = "pkgs.jirafeau";
+ };
+
+ poolConfig = mkOption {
+ type = with types; attrsOf (oneOf [ str int bool ]);
+ default = {
+ "pm" = "dynamic";
+ "pm.max_children" = 32;
+ "pm.start_servers" = 2;
+ "pm.min_spare_servers" = 2;
+ "pm.max_spare_servers" = 4;
+ "pm.max_requests" = 500;
+ };
+ description = ''
+ Options for Jirafeau PHP pool. See documentation on php-fpm.conf for
+ details on configuration directives.
+ '';
+ };
+ };
+
+
+ config = mkIf cfg.enable {
+ services = {
+ nginx = {
+ enable = true;
+ virtualHosts."${cfg.hostName}" = mkMerge [
+ cfg.nginxConfig
+ {
+ extraConfig = let
+ clientMaxBodySize =
+ if cfg.maxUploadSizeMegabytes == 0 then "0" else "${cfg.maxUploadSizeMegabytes}m";
+ in
+ ''
+ index index.php;
+ client_max_body_size ${clientMaxBodySize};
+ client_body_timeout ${cfg.maxUploadTimeout};
+ client_header_timeout ${cfg.maxUploadTimeout};
+ '';
+ locations = {
+ "~ \\.php$".extraConfig = ''
+ include ${pkgs.nginx}/conf/fastcgi_params;
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_index index.php;
+ fastcgi_pass unix:${config.services.phpfpm.pools.jirafeau.socket};
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ '';
+ };
+ root = mkForce "${cfg.package}";
+ }
+ ];
+ };
+
+ phpfpm.pools.jirafeau = {
+ inherit group user;
+ phpEnv."JIRAFEAU_CONFIG" = "${localConfig}";
+ settings = {
+ "listen.mode" = "0660";
+ "listen.owner" = user;
+ "listen.group" = group;
+ } // cfg.poolConfig;
+ };
+ };
+
+ systemd.tmpfiles.rules = [
+ "d ${cfg.dataDir} 0750 ${user} ${group} - -"
+ "d ${cfg.dataDir}/files/ 0750 ${user} ${group} - -"
+ "d ${cfg.dataDir}/links/ 0750 ${user} ${group} - -"
+ "d ${cfg.dataDir}/async/ 0750 ${user} ${group} - -"
+ ];
+ };
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index a854365f752..2e547780439 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -137,6 +137,7 @@ in
jackett = handleTest ./jackett.nix {};
jellyfin = handleTest ./jellyfin.nix {};
jenkins = handleTest ./jenkins.nix {};
+ jirafeau = handleTest ./jirafeau.nix {};
kafka = handleTest ./kafka.nix {};
keepalived = handleTest ./keepalived.nix {};
kerberos = handleTest ./kerberos/default.nix {};
diff --git a/nixos/tests/jirafeau.nix b/nixos/tests/jirafeau.nix
new file mode 100644
index 00000000000..0f5af7f718a
--- /dev/null
+++ b/nixos/tests/jirafeau.nix
@@ -0,0 +1,22 @@
+import ./make-test-python.nix ({ lib, ... }:
+
+with lib;
+
+{
+ name = "jirafeau";
+ meta.maintainers = with maintainers; [ davidtwco ];
+
+ nodes.machine = { pkgs, ... }: {
+ services.jirafeau = {
+ enable = true;
+ };
+ };
+
+ testScript = ''
+ machine.start()
+ machine.wait_for_unit("phpfpm-jirafeau.service")
+ machine.wait_for_unit("nginx.service")
+ machine.wait_for_open_port(80)
+ machine.succeed("curl -sSfL http://localhost/ | grep 'Jirafeau'")
+ '';
+})