@@ -1,16 +1,21 @@
1−{ config, lib, pkgs, ... }:
1+{ config, pkgs, lib, ... }:
22
33let
4+ inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types maintainers recursiveUpdate;
5+ inherit (lib) any attrValues concatMapStrings concatMapStringsSep flatten literalExample;
6+ inherit (lib) filterAttrs mapAttrs mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString;
47
5− inherit (lib) mkEnableOption mkForce mkIf mkMerge mkOption optionalAttrs recursiveUpdate types maintainers;
6− inherit (lib) concatMapStringsSep flatten mapAttrs mapAttrs' mapAttrsToList nameValuePair concatMapStringSep;
7−
8− eachSite = config.services.dokuwiki;
9−
8+ cfg = migrateOldAttrs config.services.dokuwiki;
9+ eachSite = cfg.sites;
1010 user = "dokuwiki";
11− group = config.services.nginx.group;
11+ webserver = config.services.${cfg.webserver};
12+ stateDir = hostName: "/var/lib/dokuwiki/${hostName}/data";
13+
14+ # Migrate config.services.dokuwiki.<hostName> to config.services.dokuwiki.sites.<hostName>
15+ oldSites = filterAttrs (o: _: o != "sites" && o != "webserver");
16+ migrateOldAttrs = cfg: cfg // { sites = cfg.sites // oldSites cfg; };
1217
13− dokuwikiAclAuthConfig = cfg: pkgs.writeText "acl.auth.php" ''
18+ dokuwikiAclAuthConfig = hostName: cfg: pkgs.writeText "acl.auth-${hostName}.php" ''
1419 # acl.auth.php
1520 # <?php exit()?>
1621 #
@@ -19,7 +24,7 @@ let
1924 ${toString cfg.acl}
2025 '';
2126
22− dokuwikiLocalConfig = cfg: pkgs.writeText "local.php" ''
27+ dokuwikiLocalConfig = hostName: cfg: pkgs.writeText "local-${hostName}.php" ''
2328 <?php
2429 $conf['savedir'] = '${cfg.stateDir}';
2530 $conf['superuser'] = '${toString cfg.superUser}';
@@ -28,11 +33,12 @@ let
2833 ${toString cfg.extraConfig}
2934 '';
3035
31− dokuwikiPluginsLocalConfig = cfg: pkgs.writeText "plugins.local.php" ''
36+ dokuwikiPluginsLocalConfig = hostName: cfg: pkgs.writeText "plugins.local-${hostName}.php" ''
3237 <?php
3338 ${cfg.pluginsConfig}
3439 '';
3540
41+
3642 pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec {
3743 pname = "dokuwiki-${hostName}";
3844 version = src.version;
@@ -43,13 +49,13 @@ let
4349 cp -r * $out/
4450
4551 # symlink the dokuwiki config
46− ln -s ${dokuwikiLocalConfig cfg} $out/share/dokuwiki/local.php
52+ ln -s ${dokuwikiLocalConfig hostName cfg} $out/share/dokuwiki/local.php
4753
4854 # symlink plugins config
49− ln -s ${dokuwikiPluginsLocalConfig cfg} $out/share/dokuwiki/plugins.local.php
55+ ln -s ${dokuwikiPluginsLocalConfig hostName cfg} $out/share/dokuwiki/plugins.local.php
5056
5157 # symlink acl
52− ln -s ${dokuwikiAclAuthConfig cfg} $out/share/dokuwiki/acl.auth.php
58+ ln -s ${dokuwikiAclAuthConfig hostName cfg} $out/share/dokuwiki/acl.auth.php
5359
5460 # symlink additional plugin(s) and templates(s)
5561 ${concatMapStringsSep "\n" (template: "ln -s ${template} $out/share/dokuwiki/lib/tpl/${template.name}") cfg.templates}
@@ -57,332 +63,385 @@ let
5763 '';
5864 };
5965
60− siteOpts = { config, lib, name, ...}: {
61− options = {
62− enable = mkEnableOption "DokuWiki web application.";
63−
64− package = mkOption {
65− type = types.package;
66− default = pkgs.dokuwiki;
67− description = "Which dokuwiki package to use.";
68− };
66+ siteOpts = { config, lib, name, ... }:
67+ {
68+ options = {
69+ package = mkOption {
70+ type = types.package;
71+ default = pkgs.dokuwiki;
72+ description = "Which DokuWiki package to use.";
73+ };
6974
70− hostName = mkOption {
71− type = types.str;
72− default = "localhost";
73− description = "FQDN for the instance.";
74− };
75+ stateDir = mkOption {
76+ type = types.path;
77+ default = "/var/lib/dokuwiki/${name}/data";
78+ description = "Location of the DokuWiki state directory.";
79+ };
7580
76− stateDir = mkOption {
77− type = types.path;
78− default = "/var/lib/dokuwiki/${name}/data";
79− description = "Location of the dokuwiki state directory.";
80− };
81+ acl = mkOption {
82+ type = types.nullOr types.lines;
83+ default = null;
84+ example = "* @ALL 8";
85+ description = ''
86+ Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
87+ Mutually exclusive with services.dokuwiki.aclFile
88+ Set this to a value other than null to take precedence over aclFile option.
89+
90+ Warning: Consider using aclFile instead if you do not
91+ want to store the ACL in the world-readable Nix store.
92+ '';
93+ };
8194
82− acl = mkOption {
83− type = types.nullOr types.lines;
84− default = null;
85− example = "* @ALL 8";
86− description = ''
87− Access Control Lists: see <link xlink:href="https://www.dokuwiki.org/acl"/>
88− Mutually exclusive with services.dokuwiki.aclFile
89− Set this to a value other than null to take precedence over aclFile option.
90−
91− Warning: Consider using aclFile instead if you do not
92− want to store the ACL in the world-readable Nix store.
93− '';
94− };
95+ aclFile = mkOption {
96+ type = with types; nullOr str;
97+ default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null;
98+ description = ''
99+ Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
100+ Mutually exclusive with services.dokuwiki.acl which is preferred.
101+ Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
102+ Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
103+ '';
104+ example = "/var/lib/dokuwiki/${name}/acl.auth.php";
105+ };
95106
96− aclFile = mkOption {
97− type = with types; nullOr str;
98− default = if (config.aclUse && config.acl == null) then "/var/lib/dokuwiki/${name}/acl.auth.php" else null;
99− description = ''
100− Location of the dokuwiki acl rules. Mutually exclusive with services.dokuwiki.acl
101− Mutually exclusive with services.dokuwiki.acl which is preferred.
102− Consult documentation <link xlink:href="https://www.dokuwiki.org/acl"/> for further instructions.
103− Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/acl.auth.php.dist"/>
104− '';
105− example = "/var/lib/dokuwiki/${name}/acl.auth.php";
106− };
107+ aclUse = mkOption {
108+ type = types.bool;
109+ default = true;
110+ description = ''
111+ Necessary for users to log in into the system.
112+ Also limits anonymous users. When disabled,
113+ everyone is able to create and edit content.
114+ '';
115+ };
107116
108− aclUse = mkOption {
109− type = types.bool;
110− default = true;
111− description = ''
112− Necessary for users to log in into the system.
113− Also limits anonymous users. When disabled,
114− everyone is able to create and edit content.
115− '';
116− };
117+ pluginsConfig = mkOption {
118+ type = types.lines;
119+ default = ''
120+ $plugins['authad'] = 0;
121+ $plugins['authldap'] = 0;
122+ $plugins['authmysql'] = 0;
123+ $plugins['authpgsql'] = 0;
124+ '';
125+ description = ''
126+ List of the dokuwiki (un)loaded plugins.
127+ '';
128+ };
117129
118− pluginsConfig = mkOption {
119− type = types.lines;
120− default = ''
121− $plugins['authad'] = 0;
122− $plugins['authldap'] = 0;
123− $plugins['authmysql'] = 0;
124− $plugins['authpgsql'] = 0;
125− '';
126− description = ''
127− List of the dokuwiki (un)loaded plugins.
128− '';
129− };
130+ superUser = mkOption {
131+ type = types.nullOr types.str;
132+ default = "@admin";
133+ description = ''
134+ You can set either a username, a list of usernames (“admin1,admin2”),
135+ or the name of a group by prepending an @ char to the groupname
136+ Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
137+ '';
138+ };
130139
131− superUser = mkOption {
132− type = types.nullOr types.str;
133− default = "@admin";
134− description = ''
135− You can set either a username, a list of usernames (“admin1,admin2”),
136− or the name of a group by prepending an @ char to the groupname
137− Consult documentation <link xlink:href="https://www.dokuwiki.org/config:superuser"/> for further instructions.
138− '';
139− };
140+ usersFile = mkOption {
141+ type = with types; nullOr str;
142+ default = if config.aclUse then "/var/lib/dokuwiki/${name}/users.auth.php" else null;
143+ description = ''
144+ Location of the dokuwiki users file. List of users. Format:
145+ login:passwordhash:Real Name:email:groups,comma,separated
146+ Create passwordHash easily by using:$ mkpasswd -5 password `pwgen 8 1`
147+ Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/users.auth.php.dist"/>
148+ '';
149+ example = "/var/lib/dokuwiki/${name}/users.auth.php";
150+ };
140151
141− usersFile = mkOption {
142− type = with types; nullOr str;
143− default = if config.aclUse then "/var/lib/dokuwiki/${name}/users.auth.php" else null;
144− description = ''
145− Location of the dokuwiki users file. List of users. Format:
146− login:passwordhash:Real Name:email:groups,comma,separated
147− Create passwordHash easily by using:$ mkpasswd -5 password `pwgen 8 1`
148− Example: <link xlink:href="https://github.com/splitbrain/dokuwiki/blob/master/conf/users.auth.php.dist"/>
152+ disableActions = mkOption {
153+ type = types.nullOr types.str;
154+ default = "";
155+ example = "search,register";
156+ description = ''
157+ Disable individual action modes. Refer to
158+ <link xlink:href="https://www.dokuwiki.org/config:action_modes"/>
159+ for details on supported values.
149160 '';
150− example = "/var/lib/dokuwiki/${name}/users.auth.php";
151− };
161+ };
152162
153− disableActions = mkOption {
154− type = types.nullOr types.str;
155− default = "";
156− example = "search,register";
157− description = ''
158− Disable individual action modes. Refer to
159− <link xlink:href="https://www.dokuwiki.org/config:action_modes"/>
160− for details on supported values.
161− '';
162− };
163+ plugins = mkOption {
164+ type = types.listOf types.path;
165+ default = [];
166+ description = ''
167+ List of path(s) to respective plugin(s) which are copied from the 'plugin' directory.
168+ <note><para>These plugins need to be packaged before use, see example.</para></note>
169+ '';
170+ example = ''
171+ # Let's package the icalevents plugin
172+ plugin-icalevents = pkgs.stdenv.mkDerivation {
173+ name = "icalevents";
174+ # Download the plugin from the dokuwiki site
175+ src = pkgs.fetchurl {
176+ url = "https://github.com/real-or-random/dokuwiki-plugin-icalevents/releases/download/2017-06-16/dokuwiki-plugin-icalevents-2017-06-16.zip";
177+ sha256 = "e40ed7dd6bbe7fe3363bbbecb4de481d5e42385b5a0f62f6a6ce6bf3a1f9dfa8";
178+ };
179+ sourceRoot = ".";
180+ # We need unzip to build this package
181+ buildInputs = [ pkgs.unzip ];
182+ # Installing simply means copying all files to the output directory
183+ installPhase = "mkdir -p $out; cp -R * $out/";
184+ };
163185
164− extraConfig = mkOption {
165− type = types.nullOr types.lines;
166− default = null;
167− example = ''
168− $conf['title'] = 'My Wiki';
169− $conf['userewrite'] = 1;
170− '';
171− description = ''
172− DokuWiki configuration. Refer to
173− <link xlink:href="https://www.dokuwiki.org/config"/>
174− for details on supported values.
175− '';
176− };
186+ # And then pass this theme to the plugin list like this:
187+ plugins = [ plugin-icalevents ];
188+ '';
189+ };
177190
178− plugins = mkOption {
179− type = types.listOf types.path;
180− default = [];
181− description = ''
182− List of path(s) to respective plugin(s) which are copied from the 'plugin' directory.
183− <note><para>These plugins need to be packaged before use, see example.</para></note>
184− '';
185− example = ''
186− # Let's package the icalevents plugin
187− plugin-icalevents = pkgs.stdenv.mkDerivation {
188− name = "icalevents";
189− # Download the plugin from the dokuwiki site
190− src = pkgs.fetchurl {
191− url = "https://github.com/real-or-random/dokuwiki-plugin-icalevents/releases/download/2017-06-16/dokuwiki-plugin-icalevents-2017-06-16.zip";
192− sha256 = "e40ed7dd6bbe7fe3363bbbecb4de481d5e42385b5a0f62f6a6ce6bf3a1f9dfa8";
191+ templates = mkOption {
192+ type = types.listOf types.path;
193+ default = [];
194+ description = ''
195+ List of path(s) to respective template(s) which are copied from the 'tpl' directory.
196+ <note><para>These templates need to be packaged before use, see example.</para></note>
197+ '';
198+ example = ''
199+ # Let's package the bootstrap3 theme
200+ template-bootstrap3 = pkgs.stdenv.mkDerivation {
201+ name = "bootstrap3";
202+ # Download the theme from the dokuwiki site
203+ src = pkgs.fetchurl {
204+ url = "https://github.com/giterlizzi/dokuwiki-template-bootstrap3/archive/v2019-05-22.zip";
205+ sha256 = "4de5ff31d54dd61bbccaf092c9e74c1af3a4c53e07aa59f60457a8f00cfb23a6";
206+ };
207+ # We need unzip to build this package
208+ buildInputs = [ pkgs.unzip ];
209+ # Installing simply means copying all files to the output directory
210+ installPhase = "mkdir -p $out; cp -R * $out/";
193211 };
194− sourceRoot = ".";
195− # We need unzip to build this package
196− nativeBuildInputs = [ pkgs.unzip ];
197− # Installing simply means copying all files to the output directory
198− installPhase = "mkdir -p $out; cp -R * $out/";
199− };
200−
201− # And then pass this theme to the plugin list like this:
202− plugins = [ plugin-icalevents ];
203− '';
204− };
205212
206− templates = mkOption {
207− type = types.listOf types.path;
208− default = [];
209− description = ''
210− List of path(s) to respective template(s) which are copied from the 'tpl' directory.
211− <note><para>These templates need to be packaged before use, see example.</para></note>
212− '';
213− example = ''
214− # Let's package the bootstrap3 theme
215− template-bootstrap3 = pkgs.stdenv.mkDerivation {
216− name = "bootstrap3";
217− # Download the theme from the dokuwiki site
218− src = pkgs.fetchurl {
219− url = "https://github.com/giterlizzi/dokuwiki-template-bootstrap3/archive/v2019-05-22.zip";
220− sha256 = "4de5ff31d54dd61bbccaf092c9e74c1af3a4c53e07aa59f60457a8f00cfb23a6";
221− };
222− # We need unzip to build this package
223− nativeBuildInputs = [ pkgs.unzip ];
224− # Installing simply means copying all files to the output directory
225− installPhase = "mkdir -p $out; cp -R * $out/";
226− };
227−
228− # And then pass this theme to the template list like this:
229− templates = [ template-bootstrap3 ];
230− '';
231− };
213+ # And then pass this theme to the template list like this:
214+ templates = [ template-bootstrap3 ];
215+ '';
216+ };
232217
233− poolConfig = mkOption {
234− type = with types; attrsOf (oneOf [ str int bool ]);
235− default = {
236− "pm" = "dynamic";
237− "pm.max_children" = 32;
238− "pm.start_servers" = 2;
239− "pm.min_spare_servers" = 2;
240− "pm.max_spare_servers" = 4;
241− "pm.max_requests" = 500;
218+ poolConfig = mkOption {
219+ type = with types; attrsOf (oneOf [ str int bool ]);
220+ default = {
221+ "pm" = "dynamic";
222+ "pm.max_children" = 32;
223+ "pm.start_servers" = 2;
224+ "pm.min_spare_servers" = 2;
225+ "pm.max_spare_servers" = 4;
226+ "pm.max_requests" = 500;
227+ };
228+ description = ''
229+ Options for the DokuWiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
230+ for details on configuration directives.
231+ '';
242232 };
243− description = ''
244− Options for the dokuwiki PHP pool. See the documentation on <literal>php-fpm.conf</literal>
245− for details on configuration directives.
246− '';
247− };
248233
249− nginx = mkOption {
250− type = types.submodule (
251− recursiveUpdate
252− (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) {}
253− );
254− default = {};
255− example = {
256− serverAliases = [
257− "wiki.\${config.networking.domain}"
258− ];
259− # To enable encryption and let let's encrypt take care of certificate
260− forceSSL = true;
261− enableACME = true;
234+ extraConfig = mkOption {
235+ type = types.nullOr types.lines;
236+ default = null;
237+ example = ''
238+ $conf['title'] = 'My Wiki';
239+ $conf['userewrite'] = 1;
240+ '';
241+ description = ''
242+ DokuWiki configuration. Refer to
243+ <link xlink:href="https://www.dokuwiki.org/config"/>
244+ for details on supported values.
245+ '';
262246 };
263− description = ''
264− With this option, you can customize the nginx virtualHost settings.
265− '';
247+
266248 };
249+
267250 };
268− };
269251in
270252{
271253 # interface
272254 options = {
273255 services.dokuwiki = mkOption {
274− type = types.attrsOf (types.submodule siteOpts);
256+ type = types.submodule {
257+ # Used to support old interface
258+ freeformType = types.attrsOf (types.submodule siteOpts);
259+
260+ # New interface
261+ options.sites = mkOption {
262+ type = types.attrsOf (types.submodule siteOpts);
263+ default = {};
264+ description = "Specification of one or more DokuWiki sites to serve";
265+ };
266+
267+ options.webserver = mkOption {
268+ type = types.enum [ "nginx" "caddy" ];
269+ default = "nginx";
270+ description = ''
271+ Whether to use nginx or caddy for virtual host management.
272+
273+ Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.<name></literal>.
274+ See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
275+
276+ Further apache2 configuration can be done by adapting <literal>services.httpd.virtualHosts.<name></literal>.
277+ See <xref linkend="opt-services.httpd.virtualHosts"/> for further information.
278+ '';
279+ };
280+ };
275281 default = {};
276− description = "Sepcification of one or more dokuwiki sites to serve.";
282+ description = "DokuWiki configuration";
277283 };
284+
278285 };
279286
280287 # implementation
281−
282− config = mkIf (eachSite != {}) {
283−
284− warnings = mapAttrsToList (hostName: cfg: mkIf (cfg.superUser == null) "Not setting services.dokuwiki.${hostName} superUser will impair your ability to administer DokuWiki") eachSite;
288+ config = mkIf (eachSite != {}) (mkMerge [{
285289
286290 assertions = flatten (mapAttrsToList (hostName: cfg:
287291 [{
288292 assertion = cfg.aclUse -> (cfg.acl != null || cfg.aclFile != null);
289− message = "Either services.dokuwiki.${hostName}.acl or services.dokuwiki.${hostName}.aclFile is mandatory if aclUse true";
293+ message = "Either services.dokuwiki.sites.${hostName}.acl or services.dokuwiki.sites.${hostName}.aclFile is mandatory if aclUse true";
290294 }
291295 {
292296 assertion = cfg.usersFile != null -> cfg.aclUse != false;
293− message = "services.dokuwiki.${hostName}.aclUse must must be true if usersFile is not null";
297+ message = "services.dokuwiki.sites.${hostName}.aclUse must must be true if usersFile is not null";
294298 }
295299 ]) eachSite);
296300
301+ warnings = mapAttrsToList (hostName: _: ''services.dokuwiki."${hostName}" is deprecated use services.dokuwiki.sites."${hostName}"'') (oldSites cfg);
302+
297303 services.phpfpm.pools = mapAttrs' (hostName: cfg: (
298304 nameValuePair "dokuwiki-${hostName}" {
299305 inherit user;
300− inherit group;
306+ group = webserver.group;
307+
301308 phpEnv = {
302− DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig cfg}";
303− DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig cfg}";
309+ DOKUWIKI_LOCAL_CONFIG = "${dokuwikiLocalConfig hostName cfg}";
310+ DOKUWIKI_PLUGINS_LOCAL_CONFIG = "${dokuwikiPluginsLocalConfig hostName cfg}";
304311 } // optionalAttrs (cfg.usersFile != null) {
305312 DOKUWIKI_USERS_AUTH_CONFIG = "${cfg.usersFile}";
306313 } //optionalAttrs (cfg.aclUse) {
307− DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig cfg}" else "${toString cfg.aclFile}";
314+ DOKUWIKI_ACL_AUTH_CONFIG = if (cfg.acl != null) then "${dokuwikiAclAuthConfig hostName cfg}" else "${toString cfg.aclFile}";
308315 };
309316
310317 settings = {
311− "listen.mode" = "0660";
312− "listen.owner" = user;
313− "listen.group" = group;
318+ "listen.owner" = webserver.user;
319+ "listen.group" = webserver.group;
314320 } // cfg.poolConfig;
315− })) eachSite;
316−
317− services.nginx = {
318− enable = true;
319− virtualHosts = mapAttrs (hostName: cfg: mkMerge [ cfg.nginx {
320− root = mkForce "${pkg hostName cfg}/share/dokuwiki";
321− extraConfig = lib.optionalString (cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME) "fastcgi_param HTTPS on;";
322−
323− locations."~ /(conf/|bin/|inc/|install.php)" = {
324− extraConfig = "deny all;";
325− };
321+ }
322+ )) eachSite;
326323
327− locations."~ ^/data/" = {
328− root = "${cfg.stateDir}";
329− extraConfig = "internal;";
330− };
324+ }
331325
332− locations."~ ^/lib.*\\.(js|css|gif|png|ico|jpg|jpeg)$" = {
333− extraConfig = "expires 365d;";
334− };
326+ {
327+ systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
328+ "d ${stateDir hostName}/attic 0750 ${user} ${webserver.group} - -"
329+ "d ${stateDir hostName}/cache 0750 ${user} ${webserver.group} - -"
330+ "d ${stateDir hostName}/index 0750 ${user} ${webserver.group} - -"
331+ "d ${stateDir hostName}/locks 0750 ${user} ${webserver.group} - -"
332+ "d ${stateDir hostName}/media 0750 ${user} ${webserver.group} - -"
333+ "d ${stateDir hostName}/media_attic 0750 ${user} ${webserver.group} - -"
334+ "d ${stateDir hostName}/media_meta 0750 ${user} ${webserver.group} - -"
335+ "d ${stateDir hostName}/meta 0750 ${user} ${webserver.group} - -"
336+ "d ${stateDir hostName}/pages 0750 ${user} ${webserver.group} - -"
337+ "d ${stateDir hostName}/tmp 0750 ${user} ${webserver.group} - -"
338+ ] ++ lib.optional (cfg.aclFile != null) "C ${cfg.aclFile} 0640 ${user} ${webserver.group} - ${pkg hostName cfg}/share/dokuwiki/conf/acl.auth.php.dist"
339+ ++ lib.optional (cfg.usersFile != null) "C ${cfg.usersFile} 0640 ${user} ${webserver.group} - ${pkg hostName cfg}/share/dokuwiki/conf/users.auth.php.dist"
340+ ) eachSite);
335341
336− locations."/" = {
337− priority = 1;
338− index = "doku.php";
339− extraConfig = "try_files $uri $uri/ @dokuwiki;";
340− };
342+ users.users.${user} = {
343+ group = webserver.group;
344+ isSystemUser = true;
345+ };
346+ }
341347
342− locations."@dokuwiki" = {
343− extraConfig = ''
348+ (mkIf (cfg.webserver == "nginx") {
349+ services.nginx = {
350+ enable = true;
351+ virtualHosts = mapAttrs (hostName: cfg: {
352+ serverName = mkDefault hostName;
353+ root = "${pkg hostName cfg}/share/dokuwiki";
354+
355+ locations = {
356+ "~ /(conf/|bin/|inc/|install.php)" = {
357+ extraConfig = "deny all;";
358+ };
359+
360+ "~ ^/data/" = {
361+ root = "${stateDir hostName}";
362+ extraConfig = "internal;";
363+ };
364+
365+ "~ ^/lib.*\.(js|css|gif|png|ico|jpg|jpeg)$" = {
366+ extraConfig = "expires 365d;";
367+ };
368+
369+ "/" = {
370+ priority = 1;
371+ index = "doku.php";
372+ extraConfig = ''try_files $uri $uri/ @dokuwiki;'';
373+ };
374+
375+ "@dokuwiki" = {
376+ extraConfig = ''
344377 # rewrites "doku.php/" out of the URLs if you set the userwrite setting to .htaccess in dokuwiki config page
345378 rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
346379 rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
347380 rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
348381 rewrite ^/(.*) /doku.php?id=$1&$args last;
349− '';
350− };
382+ '';
383+ };
351384
352− locations."~ \\.php$" = {
353− extraConfig = ''
385+ "~ \\.php$" = {
386+ extraConfig = ''
354387 try_files $uri $uri/ /doku.php;
355388 include ${pkgs.nginx}/conf/fastcgi_params;
356389 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
357390 fastcgi_param REDIRECT_STATUS 200;
358391 fastcgi_pass unix:${config.services.phpfpm.pools."dokuwiki-${hostName}".socket};
359− ${lib.optionalString (cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME) "fastcgi_param HTTPS on;"}
360− '';
392+ '';
393+ };
394+
361395 };
362− }]) eachSite;
396+ }) eachSite;
363397 };
398+ })
364399
365− systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
366− "d ${cfg.stateDir}/attic 0750 ${user} ${group} - -"
367− "d ${cfg.stateDir}/cache 0750 ${user} ${group} - -"
368− "d ${cfg.stateDir}/index 0750 ${user} ${group} - -"
369− "d ${cfg.stateDir}/locks 0750 ${user} ${group} - -"
370− "d ${cfg.stateDir}/media 0750 ${user} ${group} - -"
371− "d ${cfg.stateDir}/media_attic 0750 ${user} ${group} - -"
372− "d ${cfg.stateDir}/media_meta 0750 ${user} ${group} - -"
373− "d ${cfg.stateDir}/meta 0750 ${user} ${group} - -"
374− "d ${cfg.stateDir}/pages 0750 ${user} ${group} - -"
375− "d ${cfg.stateDir}/tmp 0750 ${user} ${group} - -"
376− ] ++ lib.optional (cfg.aclFile != null) "C ${cfg.aclFile} 0640 ${user} ${group} - ${pkg hostName cfg}/share/dokuwiki/conf/acl.auth.php.dist"
377− ++ lib.optional (cfg.usersFile != null) "C ${cfg.usersFile} 0640 ${user} ${group} - ${pkg hostName cfg}/share/dokuwiki/conf/users.auth.php.dist"
378− ) eachSite);
400+ (mkIf (cfg.webserver == "caddy") {
401+ services.caddy = {
402+ enable = true;
403+ virtualHosts = mapAttrs' (hostName: cfg: (
404+ nameValuePair "http://${hostName}" {
405+ extraConfig = ''
406+ root * ${pkg hostName cfg}/share/dokuwiki
407+ file_server
379408
380− users.users.${user} = {
381− group = group;
382− isSystemUser = true;
409+ encode zstd gzip
410+ php_fastcgi unix/${config.services.phpfpm.pools."dokuwiki-${hostName}".socket}
411+
412+ @restrict_files {
413+ path /data/* /conf/* /bin/* /inc/* /vendor/* /install.php
414+ }
415+
416+ respond @restrict_files 404
417+
418+ @allow_media {
419+ path_regexp path ^/_media/(.*)$
420+ }
421+ rewrite @allow_media /lib/exe/fetch.php?media=/{http.regexp.path.1}
422+
423+ @allow_detail {
424+ path /_detail*
425+ }
426+ rewrite @allow_detail /lib/exe/detail.php?media={path}
427+
428+ @allow_export {
429+ path /_export*
430+ path_regexp export /([^/]+)/(.*)
431+ }
432+ rewrite @allow_export /doku.php?do=export_{http.regexp.export.1}&id={http.regexp.export.2}
433+
434+ try_files {path} {path}/ /doku.php?id={path}&{query}
435+ '';
436+ }
437+ )) eachSite;
383438 };
384− };
439+ })
385440
386− meta.maintainers = with maintainers; [ _1000101 ];
441+ ]);
387442
443+ meta.maintainers = with maintainers; [
444+ _1000101
445+ onny
446+ ];
388447}