diff options
Diffstat (limited to 'virtual/modules/websites/apache')
-rw-r--r-- | virtual/modules/websites/apache/httpd_inte.nix | 715 | ||||
-rw-r--r-- | virtual/modules/websites/apache/httpd_prod.nix | 715 | ||||
-rw-r--r-- | virtual/modules/websites/apache/httpd_tools.nix | 727 | ||||
-rw-r--r-- | virtual/modules/websites/apache/per-server-options.nix | 188 |
4 files changed, 0 insertions, 2345 deletions
diff --git a/virtual/modules/websites/apache/httpd_inte.nix b/virtual/modules/websites/apache/httpd_inte.nix deleted file mode 100644 index 0417281..0000000 --- a/virtual/modules/websites/apache/httpd_inte.nix +++ /dev/null | |||
@@ -1,715 +0,0 @@ | |||
1 | { config, lib, pkgs, ... }: | ||
2 | |||
3 | with lib; | ||
4 | |||
5 | let | ||
6 | |||
7 | mainCfg = config.services.httpdInte; | ||
8 | |||
9 | httpd = mainCfg.package.out; | ||
10 | |||
11 | version24 = !versionOlder httpd.version "2.4"; | ||
12 | |||
13 | httpdConf = mainCfg.configFile; | ||
14 | |||
15 | php = mainCfg.phpPackage.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ }; | ||
16 | |||
17 | phpMajorVersion = head (splitString "." php.version); | ||
18 | |||
19 | mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; }; | ||
20 | |||
21 | defaultListen = cfg: if cfg.enableSSL | ||
22 | then [{ip = "*"; port = 443;}] | ||
23 | else [{ip = "*"; port = 80;}]; | ||
24 | |||
25 | getListen = cfg: | ||
26 | let list = (lib.optional (cfg.port != 0) {ip = "*"; port = cfg.port;}) ++ cfg.listen; | ||
27 | in if list == [] | ||
28 | then defaultListen cfg | ||
29 | else list; | ||
30 | |||
31 | listenToString = l: "${l.ip}:${toString l.port}"; | ||
32 | |||
33 | extraModules = attrByPath ["extraModules"] [] mainCfg; | ||
34 | extraForeignModules = filter isAttrs extraModules; | ||
35 | extraApacheModules = filter isString extraModules; | ||
36 | |||
37 | |||
38 | makeServerInfo = cfg: { | ||
39 | # Canonical name must not include a trailing slash. | ||
40 | canonicalNames = | ||
41 | let defaultPort = (head (defaultListen cfg)).port; in | ||
42 | map (port: | ||
43 | (if cfg.enableSSL then "https" else "http") + "://" + | ||
44 | cfg.hostName + | ||
45 | (if port != defaultPort then ":${toString port}" else "") | ||
46 | ) (map (x: x.port) (getListen cfg)); | ||
47 | |||
48 | # Admin address: inherit from the main server if not specified for | ||
49 | # a virtual host. | ||
50 | adminAddr = if cfg.adminAddr != null then cfg.adminAddr else mainCfg.adminAddr; | ||
51 | |||
52 | vhostConfig = cfg; | ||
53 | serverConfig = mainCfg; | ||
54 | fullConfig = config; # machine config | ||
55 | }; | ||
56 | |||
57 | |||
58 | allHosts = [mainCfg] ++ mainCfg.virtualHosts; | ||
59 | |||
60 | |||
61 | callSubservices = serverInfo: defs: | ||
62 | let f = svc: | ||
63 | let | ||
64 | svcFunction = | ||
65 | if svc ? function then svc.function | ||
66 | # instead of using serviceType="mediawiki"; you can copy mediawiki.nix to any location outside nixpkgs, modify it at will, and use serviceExpression=./mediawiki.nix; | ||
67 | else if svc ? serviceExpression then import (toString svc.serviceExpression) | ||
68 | else import (toString "${toString ./.}/${if svc ? serviceType then svc.serviceType else svc.serviceName}.nix"); | ||
69 | config = (evalModules | ||
70 | { modules = [ { options = res.options; config = svc.config or svc; } ]; | ||
71 | check = false; | ||
72 | }).config; | ||
73 | defaults = { | ||
74 | extraConfig = ""; | ||
75 | extraModules = []; | ||
76 | extraModulesPre = []; | ||
77 | extraPath = []; | ||
78 | extraServerPath = []; | ||
79 | globalEnvVars = []; | ||
80 | robotsEntries = ""; | ||
81 | startupScript = ""; | ||
82 | enablePHP = false; | ||
83 | enablePerl = false; | ||
84 | phpOptions = ""; | ||
85 | options = {}; | ||
86 | documentRoot = null; | ||
87 | }; | ||
88 | res = defaults // svcFunction { inherit config lib pkgs serverInfo php; }; | ||
89 | in res; | ||
90 | in map f defs; | ||
91 | |||
92 | |||
93 | # !!! callSubservices is expensive | ||
94 | subservicesFor = cfg: callSubservices (makeServerInfo cfg) cfg.extraSubservices; | ||
95 | |||
96 | mainSubservices = subservicesFor mainCfg; | ||
97 | |||
98 | allSubservices = mainSubservices ++ concatMap subservicesFor mainCfg.virtualHosts; | ||
99 | |||
100 | |||
101 | enableSSL = any (vhost: vhost.enableSSL) allHosts; | ||
102 | |||
103 | |||
104 | # Names of modules from ${httpd}/modules that we want to load. | ||
105 | apacheModules = | ||
106 | [ # HTTP authentication mechanisms: basic and digest. | ||
107 | "auth_basic" "auth_digest" | ||
108 | |||
109 | # Authentication: is the user who he claims to be? | ||
110 | "authn_file" "authn_dbm" "authn_anon" | ||
111 | (if version24 then "authn_core" else "authn_alias") | ||
112 | |||
113 | # Authorization: is the user allowed access? | ||
114 | "authz_user" "authz_groupfile" "authz_host" | ||
115 | |||
116 | # Other modules. | ||
117 | "ext_filter" "include" "log_config" "env" "mime_magic" | ||
118 | "cern_meta" "expires" "headers" "usertrack" /* "unique_id" */ "setenvif" | ||
119 | "mime" "dav" "status" "autoindex" "asis" "info" "dav_fs" | ||
120 | "vhost_alias" "negotiation" "dir" "imagemap" "actions" "speling" | ||
121 | "userdir" "alias" "rewrite" "proxy" "proxy_http" | ||
122 | ] | ||
123 | ++ optionals version24 [ | ||
124 | "mpm_${mainCfg.multiProcessingModule}" | ||
125 | "authz_core" | ||
126 | "unixd" | ||
127 | "cache" "cache_disk" | ||
128 | "slotmem_shm" | ||
129 | "socache_shmcb" | ||
130 | # For compatibility with old configurations, the new module mod_access_compat is provided. | ||
131 | "access_compat" | ||
132 | ] | ||
133 | ++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ]) | ||
134 | ++ optional enableSSL "ssl" | ||
135 | ++ extraApacheModules; | ||
136 | |||
137 | |||
138 | allDenied = if version24 then '' | ||
139 | Require all denied | ||
140 | '' else '' | ||
141 | Order deny,allow | ||
142 | Deny from all | ||
143 | ''; | ||
144 | |||
145 | allGranted = if version24 then '' | ||
146 | Require all granted | ||
147 | '' else '' | ||
148 | Order allow,deny | ||
149 | Allow from all | ||
150 | ''; | ||
151 | |||
152 | |||
153 | loggingConf = (if mainCfg.logFormat != "none" then '' | ||
154 | ErrorLog ${mainCfg.logDir}/error_log | ||
155 | |||
156 | LogLevel notice | ||
157 | |||
158 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined | ||
159 | LogFormat "%h %l %u %t \"%r\" %>s %b" common | ||
160 | LogFormat "%{Referer}i -> %U" referer | ||
161 | LogFormat "%{User-agent}i" agent | ||
162 | |||
163 | CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat} | ||
164 | '' else '' | ||
165 | ErrorLog /dev/null | ||
166 | ''); | ||
167 | |||
168 | |||
169 | browserHacks = '' | ||
170 | BrowserMatch "Mozilla/2" nokeepalive | ||
171 | BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 | ||
172 | BrowserMatch "RealPlayer 4\.0" force-response-1.0 | ||
173 | BrowserMatch "Java/1\.0" force-response-1.0 | ||
174 | BrowserMatch "JDK/1\.0" force-response-1.0 | ||
175 | BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully | ||
176 | BrowserMatch "^WebDrive" redirect-carefully | ||
177 | BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully | ||
178 | BrowserMatch "^gnome-vfs" redirect-carefully | ||
179 | ''; | ||
180 | |||
181 | |||
182 | sslConf = '' | ||
183 | SSLSessionCache ${if version24 then "shmcb" else "shm"}:${mainCfg.stateDir}/ssl_scache(512000) | ||
184 | |||
185 | ${if version24 then "Mutex" else "SSLMutex"} posixsem | ||
186 | |||
187 | SSLRandomSeed startup builtin | ||
188 | SSLRandomSeed connect builtin | ||
189 | |||
190 | SSLProtocol All -SSLv2 -SSLv3 | ||
191 | SSLCipherSuite HIGH:!aNULL:!MD5:!EXP | ||
192 | SSLHonorCipherOrder on | ||
193 | ''; | ||
194 | |||
195 | |||
196 | mimeConf = '' | ||
197 | TypesConfig ${httpd}/conf/mime.types | ||
198 | |||
199 | AddType application/x-x509-ca-cert .crt | ||
200 | AddType application/x-pkcs7-crl .crl | ||
201 | AddType application/x-httpd-php .php .phtml | ||
202 | |||
203 | <IfModule mod_mime_magic.c> | ||
204 | MIMEMagicFile ${httpd}/conf/magic | ||
205 | </IfModule> | ||
206 | ''; | ||
207 | |||
208 | |||
209 | perServerConf = isMainServer: cfg: let | ||
210 | |||
211 | serverInfo = makeServerInfo cfg; | ||
212 | |||
213 | subservices = callSubservices serverInfo cfg.extraSubservices; | ||
214 | |||
215 | maybeDocumentRoot = fold (svc: acc: | ||
216 | if acc == null then svc.documentRoot else assert svc.documentRoot == null; acc | ||
217 | ) null ([ cfg ] ++ subservices); | ||
218 | |||
219 | documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else | ||
220 | pkgs.runCommand "empty" {} "mkdir -p $out"; | ||
221 | |||
222 | documentRootConf = '' | ||
223 | DocumentRoot "${documentRoot}" | ||
224 | |||
225 | <Directory "${documentRoot}"> | ||
226 | Options Indexes FollowSymLinks | ||
227 | AllowOverride None | ||
228 | ${allGranted} | ||
229 | </Directory> | ||
230 | ''; | ||
231 | |||
232 | robotsTxt = | ||
233 | concatStringsSep "\n" (filter (x: x != "") ( | ||
234 | # If this is a vhost, the include the entries for the main server as well. | ||
235 | (if isMainServer then [] else [mainCfg.robotsEntries] ++ map (svc: svc.robotsEntries) mainSubservices) | ||
236 | ++ [cfg.robotsEntries] | ||
237 | ++ (map (svc: svc.robotsEntries) subservices))); | ||
238 | |||
239 | in '' | ||
240 | ${concatStringsSep "\n" (map (n: "ServerName ${n}") serverInfo.canonicalNames)} | ||
241 | |||
242 | ${concatMapStrings (alias: "ServerAlias ${alias}\n") cfg.serverAliases} | ||
243 | |||
244 | ${if cfg.sslServerCert != null then '' | ||
245 | SSLCertificateFile ${cfg.sslServerCert} | ||
246 | SSLCertificateKeyFile ${cfg.sslServerKey} | ||
247 | ${if cfg.sslServerChain != null then '' | ||
248 | SSLCertificateChainFile ${cfg.sslServerChain} | ||
249 | '' else ""} | ||
250 | '' else ""} | ||
251 | |||
252 | ${if cfg.enableSSL then '' | ||
253 | SSLEngine on | ||
254 | '' else if enableSSL then /* i.e., SSL is enabled for some host, but not this one */ | ||
255 | '' | ||
256 | SSLEngine off | ||
257 | '' else ""} | ||
258 | |||
259 | ${if isMainServer || cfg.adminAddr != null then '' | ||
260 | ServerAdmin ${cfg.adminAddr} | ||
261 | '' else ""} | ||
262 | |||
263 | ${if !isMainServer && mainCfg.logPerVirtualHost then '' | ||
264 | ErrorLog ${mainCfg.logDir}/error_log-${cfg.hostName} | ||
265 | CustomLog ${mainCfg.logDir}/access_log-${cfg.hostName} ${cfg.logFormat} | ||
266 | '' else ""} | ||
267 | |||
268 | ${optionalString (robotsTxt != "") '' | ||
269 | Alias /robots.txt ${pkgs.writeText "robots.txt" robotsTxt} | ||
270 | ''} | ||
271 | |||
272 | ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""} | ||
273 | |||
274 | ${if cfg.enableUserDir then '' | ||
275 | |||
276 | UserDir public_html | ||
277 | UserDir disabled root | ||
278 | |||
279 | <Directory "/home/*/public_html"> | ||
280 | AllowOverride FileInfo AuthConfig Limit Indexes | ||
281 | Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec | ||
282 | <Limit GET POST OPTIONS> | ||
283 | ${allGranted} | ||
284 | </Limit> | ||
285 | <LimitExcept GET POST OPTIONS> | ||
286 | ${allDenied} | ||
287 | </LimitExcept> | ||
288 | </Directory> | ||
289 | |||
290 | '' else ""} | ||
291 | |||
292 | ${if cfg.globalRedirect != null && cfg.globalRedirect != "" then '' | ||
293 | RedirectPermanent / ${cfg.globalRedirect} | ||
294 | '' else ""} | ||
295 | |||
296 | ${ | ||
297 | let makeFileConf = elem: '' | ||
298 | Alias ${elem.urlPath} ${elem.file} | ||
299 | ''; | ||
300 | in concatMapStrings makeFileConf cfg.servedFiles | ||
301 | } | ||
302 | |||
303 | ${ | ||
304 | let makeDirConf = elem: '' | ||
305 | Alias ${elem.urlPath} ${elem.dir}/ | ||
306 | <Directory ${elem.dir}> | ||
307 | Options +Indexes | ||
308 | ${allGranted} | ||
309 | AllowOverride All | ||
310 | </Directory> | ||
311 | ''; | ||
312 | in concatMapStrings makeDirConf cfg.servedDirs | ||
313 | } | ||
314 | |||
315 | ${concatMapStrings (svc: svc.extraConfig) subservices} | ||
316 | |||
317 | ${cfg.extraConfig} | ||
318 | ''; | ||
319 | |||
320 | |||
321 | confFile = pkgs.writeText "httpd.conf" '' | ||
322 | |||
323 | ServerRoot ${httpd} | ||
324 | |||
325 | ${optionalString version24 '' | ||
326 | DefaultRuntimeDir ${mainCfg.stateDir}/runtime | ||
327 | ''} | ||
328 | |||
329 | PidFile ${mainCfg.stateDir}/httpd.pid | ||
330 | |||
331 | ${optionalString (mainCfg.multiProcessingModule != "prefork") '' | ||
332 | # mod_cgid requires this. | ||
333 | ScriptSock ${mainCfg.stateDir}/cgisock | ||
334 | ''} | ||
335 | |||
336 | <IfModule prefork.c> | ||
337 | MaxClients ${toString mainCfg.maxClients} | ||
338 | MaxRequestsPerChild ${toString mainCfg.maxRequestsPerChild} | ||
339 | </IfModule> | ||
340 | |||
341 | ${let | ||
342 | listen = concatMap getListen allHosts; | ||
343 | toStr = listen: "Listen ${listenToString listen}\n"; | ||
344 | uniqueListen = uniqList {inputList = map toStr listen;}; | ||
345 | in concatStrings uniqueListen | ||
346 | } | ||
347 | |||
348 | User ${mainCfg.user} | ||
349 | Group ${mainCfg.group} | ||
350 | |||
351 | ${let | ||
352 | load = {name, path}: "LoadModule ${name}_module ${path}\n"; | ||
353 | allModules = | ||
354 | concatMap (svc: svc.extraModulesPre) allSubservices | ||
355 | ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules | ||
356 | ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; } | ||
357 | ++ optional enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; } | ||
358 | ++ optional enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; } | ||
359 | ++ concatMap (svc: svc.extraModules) allSubservices | ||
360 | ++ extraForeignModules; | ||
361 | in concatMapStrings load allModules | ||
362 | } | ||
363 | |||
364 | AddHandler type-map var | ||
365 | |||
366 | <Files ~ "^\.ht"> | ||
367 | ${allDenied} | ||
368 | </Files> | ||
369 | |||
370 | ${mimeConf} | ||
371 | ${loggingConf} | ||
372 | ${browserHacks} | ||
373 | |||
374 | Include ${httpd}/conf/extra/httpd-default.conf | ||
375 | Include ${httpd}/conf/extra/httpd-autoindex.conf | ||
376 | Include ${httpd}/conf/extra/httpd-multilang-errordoc.conf | ||
377 | Include ${httpd}/conf/extra/httpd-languages.conf | ||
378 | |||
379 | ${if enableSSL then sslConf else ""} | ||
380 | |||
381 | # Fascist default - deny access to everything. | ||
382 | <Directory /> | ||
383 | Options FollowSymLinks | ||
384 | AllowOverride None | ||
385 | ${allDenied} | ||
386 | </Directory> | ||
387 | |||
388 | # Generate directives for the main server. | ||
389 | ${perServerConf true mainCfg} | ||
390 | |||
391 | # Always enable virtual hosts; it doesn't seem to hurt. | ||
392 | ${let | ||
393 | listen = concatMap getListen allHosts; | ||
394 | uniqueListen = uniqList {inputList = listen;}; | ||
395 | directives = concatMapStrings (listen: "NameVirtualHost ${listenToString listen}\n") uniqueListen; | ||
396 | in optionalString (!version24) directives | ||
397 | } | ||
398 | |||
399 | ${let | ||
400 | makeVirtualHost = vhost: '' | ||
401 | <VirtualHost ${concatStringsSep " " (map listenToString (getListen vhost))}> | ||
402 | ${perServerConf false vhost} | ||
403 | </VirtualHost> | ||
404 | ''; | ||
405 | in concatMapStrings makeVirtualHost mainCfg.virtualHosts | ||
406 | } | ||
407 | ''; | ||
408 | |||
409 | |||
410 | enablePHP = mainCfg.enablePHP || any (svc: svc.enablePHP) allSubservices; | ||
411 | |||
412 | enablePerl = mainCfg.enablePerl || any (svc: svc.enablePerl) allSubservices; | ||
413 | |||
414 | |||
415 | # Generate the PHP configuration file. Should probably be factored | ||
416 | # out into a separate module. | ||
417 | phpIni = pkgs.runCommand "php.ini" | ||
418 | { options = concatStringsSep "\n" | ||
419 | ([ mainCfg.phpOptions ] ++ (map (svc: svc.phpOptions) allSubservices)); | ||
420 | } | ||
421 | '' | ||
422 | cat ${php}/etc/php.ini > $out | ||
423 | echo "$options" >> $out | ||
424 | ''; | ||
425 | |||
426 | in | ||
427 | |||
428 | |||
429 | { | ||
430 | |||
431 | ###### interface | ||
432 | |||
433 | options = { | ||
434 | |||
435 | services.httpdInte = { | ||
436 | |||
437 | enable = mkOption { | ||
438 | type = types.bool; | ||
439 | default = false; | ||
440 | description = "Whether to enable the Apache HTTP Server."; | ||
441 | }; | ||
442 | |||
443 | package = mkOption { | ||
444 | type = types.package; | ||
445 | default = pkgs.apacheHttpd; | ||
446 | defaultText = "pkgs.apacheHttpd"; | ||
447 | description = '' | ||
448 | Overridable attribute of the Apache HTTP Server package to use. | ||
449 | ''; | ||
450 | }; | ||
451 | |||
452 | configFile = mkOption { | ||
453 | type = types.path; | ||
454 | default = confFile; | ||
455 | defaultText = "confFile"; | ||
456 | example = literalExample ''pkgs.writeText "httpd.conf" "# my custom config file ..."''; | ||
457 | description = '' | ||
458 | Override the configuration file used by Apache. By default, | ||
459 | NixOS generates one automatically. | ||
460 | ''; | ||
461 | }; | ||
462 | |||
463 | extraConfig = mkOption { | ||
464 | type = types.lines; | ||
465 | default = ""; | ||
466 | description = '' | ||
467 | Cnfiguration lines appended to the generated Apache | ||
468 | configuration file. Note that this mechanism may not work | ||
469 | when <option>configFile</option> is overridden. | ||
470 | ''; | ||
471 | }; | ||
472 | |||
473 | extraModules = mkOption { | ||
474 | type = types.listOf types.unspecified; | ||
475 | default = []; | ||
476 | example = literalExample ''[ "proxy_connect" { name = "php5"; path = "''${pkgs.php}/modules/libphp5.so"; } ]''; | ||
477 | description = '' | ||
478 | Additional Apache modules to be used. These can be | ||
479 | specified as a string in the case of modules distributed | ||
480 | with Apache, or as an attribute set specifying the | ||
481 | <varname>name</varname> and <varname>path</varname> of the | ||
482 | module. | ||
483 | ''; | ||
484 | }; | ||
485 | |||
486 | logPerVirtualHost = mkOption { | ||
487 | type = types.bool; | ||
488 | default = false; | ||
489 | description = '' | ||
490 | If enabled, each virtual host gets its own | ||
491 | <filename>access_log</filename> and | ||
492 | <filename>error_log</filename>, namely suffixed by the | ||
493 | <option>hostName</option> of the virtual host. | ||
494 | ''; | ||
495 | }; | ||
496 | |||
497 | user = mkOption { | ||
498 | type = types.str; | ||
499 | default = "wwwrun"; | ||
500 | description = '' | ||
501 | User account under which httpd runs. The account is created | ||
502 | automatically if it doesn't exist. | ||
503 | ''; | ||
504 | }; | ||
505 | |||
506 | group = mkOption { | ||
507 | type = types.str; | ||
508 | default = "wwwrun"; | ||
509 | description = '' | ||
510 | Group under which httpd runs. The account is created | ||
511 | automatically if it doesn't exist. | ||
512 | ''; | ||
513 | }; | ||
514 | |||
515 | logDir = mkOption { | ||
516 | type = types.path; | ||
517 | default = "/var/log/httpd"; | ||
518 | description = '' | ||
519 | Directory for Apache's log files. It is created automatically. | ||
520 | ''; | ||
521 | }; | ||
522 | |||
523 | stateDir = mkOption { | ||
524 | type = types.path; | ||
525 | default = "/run/httpd"; | ||
526 | description = '' | ||
527 | Directory for Apache's transient runtime state (such as PID | ||
528 | files). It is created automatically. Note that the default, | ||
529 | <filename>/run/httpd</filename>, is deleted at boot time. | ||
530 | ''; | ||
531 | }; | ||
532 | |||
533 | virtualHosts = mkOption { | ||
534 | type = types.listOf (types.submodule ( | ||
535 | { options = import ./per-server-options.nix { | ||
536 | inherit lib; | ||
537 | forMainServer = false; | ||
538 | }; | ||
539 | })); | ||
540 | default = []; | ||
541 | example = [ | ||
542 | { hostName = "foo"; | ||
543 | documentRoot = "/data/webroot-foo"; | ||
544 | } | ||
545 | { hostName = "bar"; | ||
546 | documentRoot = "/data/webroot-bar"; | ||
547 | } | ||
548 | ]; | ||
549 | description = '' | ||
550 | Specification of the virtual hosts served by Apache. Each | ||
551 | element should be an attribute set specifying the | ||
552 | configuration of the virtual host. The available options | ||
553 | are the non-global options permissible for the main host. | ||
554 | ''; | ||
555 | }; | ||
556 | |||
557 | enableMellon = mkOption { | ||
558 | type = types.bool; | ||
559 | default = false; | ||
560 | description = "Whether to enable the mod_auth_mellon module."; | ||
561 | }; | ||
562 | |||
563 | enablePHP = mkOption { | ||
564 | type = types.bool; | ||
565 | default = false; | ||
566 | description = "Whether to enable the PHP module."; | ||
567 | }; | ||
568 | |||
569 | phpPackage = mkOption { | ||
570 | type = types.package; | ||
571 | default = pkgs.php; | ||
572 | defaultText = "pkgs.php"; | ||
573 | description = '' | ||
574 | Overridable attribute of the PHP package to use. | ||
575 | ''; | ||
576 | }; | ||
577 | |||
578 | enablePerl = mkOption { | ||
579 | type = types.bool; | ||
580 | default = false; | ||
581 | description = "Whether to enable the Perl module (mod_perl)."; | ||
582 | }; | ||
583 | |||
584 | phpOptions = mkOption { | ||
585 | type = types.lines; | ||
586 | default = ""; | ||
587 | example = | ||
588 | '' | ||
589 | date.timezone = "CET" | ||
590 | ''; | ||
591 | description = | ||
592 | "Options appended to the PHP configuration file <filename>php.ini</filename>."; | ||
593 | }; | ||
594 | |||
595 | multiProcessingModule = mkOption { | ||
596 | type = types.str; | ||
597 | default = "prefork"; | ||
598 | example = "worker"; | ||
599 | description = | ||
600 | '' | ||
601 | Multi-processing module to be used by Apache. Available | ||
602 | modules are <literal>prefork</literal> (the default; | ||
603 | handles each request in a separate child process), | ||
604 | <literal>worker</literal> (hybrid approach that starts a | ||
605 | number of child processes each running a number of | ||
606 | threads) and <literal>event</literal> (a recent variant of | ||
607 | <literal>worker</literal> that handles persistent | ||
608 | connections more efficiently). | ||
609 | ''; | ||
610 | }; | ||
611 | |||
612 | maxClients = mkOption { | ||
613 | type = types.int; | ||
614 | default = 150; | ||
615 | example = 8; | ||
616 | description = "Maximum number of httpd processes (prefork)"; | ||
617 | }; | ||
618 | |||
619 | maxRequestsPerChild = mkOption { | ||
620 | type = types.int; | ||
621 | default = 0; | ||
622 | example = 500; | ||
623 | description = | ||
624 | "Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited"; | ||
625 | }; | ||
626 | } | ||
627 | |||
628 | # Include the options shared between the main server and virtual hosts. | ||
629 | // (import ./per-server-options.nix { | ||
630 | inherit lib; | ||
631 | forMainServer = true; | ||
632 | }); | ||
633 | |||
634 | }; | ||
635 | |||
636 | |||
637 | ###### implementation | ||
638 | |||
639 | config = mkIf config.services.httpdInte.enable { | ||
640 | |||
641 | assertions = [ { assertion = mainCfg.enableSSL == true | ||
642 | -> mainCfg.sslServerCert != null | ||
643 | && mainCfg.sslServerKey != null; | ||
644 | message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; } | ||
645 | ]; | ||
646 | |||
647 | warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port};}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts); | ||
648 | |||
649 | environment.systemPackages = [httpd] ++ concatMap (svc: svc.extraPath) allSubservices; | ||
650 | |||
651 | services.httpdInte.phpOptions = | ||
652 | '' | ||
653 | ; Needed for PHP's mail() function. | ||
654 | sendmail_path = sendmail -t -i | ||
655 | '' + optionalString (!isNull config.time.timeZone) '' | ||
656 | |||
657 | ; Apparently PHP doesn't use $TZ. | ||
658 | date.timezone = "${config.time.timeZone}" | ||
659 | ''; | ||
660 | |||
661 | systemd.services.httpdInte = | ||
662 | { description = "Apache HTTPD"; | ||
663 | |||
664 | wantedBy = [ "multi-user.target" ]; | ||
665 | wants = [ "keys.target" ]; | ||
666 | after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ]; | ||
667 | |||
668 | path = | ||
669 | [ httpd pkgs.coreutils pkgs.gnugrep ] | ||
670 | ++ # Needed for PHP's mail() function. !!! Probably the | ||
671 | # ssmtp module should export the path to sendmail in | ||
672 | # some way. | ||
673 | optional config.networking.defaultMailServer.directDelivery pkgs.ssmtp | ||
674 | ++ concatMap (svc: svc.extraServerPath) allSubservices; | ||
675 | |||
676 | environment = | ||
677 | optionalAttrs enablePHP { PHPRC = phpIni; } | ||
678 | // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; } | ||
679 | // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices)); | ||
680 | |||
681 | preStart = | ||
682 | '' | ||
683 | mkdir -m 0750 -p ${mainCfg.stateDir} | ||
684 | [ $(id -u) != 0 ] || chown root.${mainCfg.group} ${mainCfg.stateDir} | ||
685 | ${optionalString version24 '' | ||
686 | mkdir -m 0750 -p "${mainCfg.stateDir}/runtime" | ||
687 | [ $(id -u) != 0 ] || chown root.${mainCfg.group} "${mainCfg.stateDir}/runtime" | ||
688 | ''} | ||
689 | mkdir -m 0700 -p ${mainCfg.logDir} | ||
690 | |||
691 | # Get rid of old semaphores. These tend to accumulate across | ||
692 | # server restarts, eventually preventing it from restarting | ||
693 | # successfully. | ||
694 | for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${mainCfg.user} ' | cut -f2 -d ' '); do | ||
695 | ${pkgs.utillinux}/bin/ipcrm -s $i | ||
696 | done | ||
697 | |||
698 | # Run the startup hooks for the subservices. | ||
699 | for i in ${toString (map (svn: svn.startupScript) allSubservices)}; do | ||
700 | echo Running Apache startup hook $i... | ||
701 | $i | ||
702 | done | ||
703 | ''; | ||
704 | |||
705 | serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf}"; | ||
706 | serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop"; | ||
707 | serviceConfig.ExecReload = "${httpd}/bin/httpd -f ${httpdConf} -k graceful"; | ||
708 | serviceConfig.Type = "forking"; | ||
709 | serviceConfig.PIDFile = "${mainCfg.stateDir}/httpd.pid"; | ||
710 | serviceConfig.Restart = "always"; | ||
711 | serviceConfig.RestartSec = "5s"; | ||
712 | }; | ||
713 | |||
714 | }; | ||
715 | } | ||
diff --git a/virtual/modules/websites/apache/httpd_prod.nix b/virtual/modules/websites/apache/httpd_prod.nix deleted file mode 100644 index 5aee602..0000000 --- a/virtual/modules/websites/apache/httpd_prod.nix +++ /dev/null | |||
@@ -1,715 +0,0 @@ | |||
1 | { config, lib, pkgs, ... }: | ||
2 | |||
3 | with lib; | ||
4 | |||
5 | let | ||
6 | |||
7 | mainCfg = config.services.httpdProd; | ||
8 | |||
9 | httpd = mainCfg.package.out; | ||
10 | |||
11 | version24 = !versionOlder httpd.version "2.4"; | ||
12 | |||
13 | httpdConf = mainCfg.configFile; | ||
14 | |||
15 | php = mainCfg.phpPackage.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ }; | ||
16 | |||
17 | phpMajorVersion = head (splitString "." php.version); | ||
18 | |||
19 | mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; }; | ||
20 | |||
21 | defaultListen = cfg: if cfg.enableSSL | ||
22 | then [{ip = "*"; port = 443;}] | ||
23 | else [{ip = "*"; port = 80;}]; | ||
24 | |||
25 | getListen = cfg: | ||
26 | let list = (lib.optional (cfg.port != 0) {ip = "*"; port = cfg.port;}) ++ cfg.listen; | ||
27 | in if list == [] | ||
28 | then defaultListen cfg | ||
29 | else list; | ||
30 | |||
31 | listenToString = l: "${l.ip}:${toString l.port}"; | ||
32 | |||
33 | extraModules = attrByPath ["extraModules"] [] mainCfg; | ||
34 | extraForeignModules = filter isAttrs extraModules; | ||
35 | extraApacheModules = filter isString extraModules; | ||
36 | |||
37 | |||
38 | makeServerInfo = cfg: { | ||
39 | # Canonical name must not include a trailing slash. | ||
40 | canonicalNames = | ||
41 | let defaultPort = (head (defaultListen cfg)).port; in | ||
42 | map (port: | ||
43 | (if cfg.enableSSL then "https" else "http") + "://" + | ||
44 | cfg.hostName + | ||
45 | (if port != defaultPort then ":${toString port}" else "") | ||
46 | ) (map (x: x.port) (getListen cfg)); | ||
47 | |||
48 | # Admin address: inherit from the main server if not specified for | ||
49 | # a virtual host. | ||
50 | adminAddr = if cfg.adminAddr != null then cfg.adminAddr else mainCfg.adminAddr; | ||
51 | |||
52 | vhostConfig = cfg; | ||
53 | serverConfig = mainCfg; | ||
54 | fullConfig = config; # machine config | ||
55 | }; | ||
56 | |||
57 | |||
58 | allHosts = [mainCfg] ++ mainCfg.virtualHosts; | ||
59 | |||
60 | |||
61 | callSubservices = serverInfo: defs: | ||
62 | let f = svc: | ||
63 | let | ||
64 | svcFunction = | ||
65 | if svc ? function then svc.function | ||
66 | # instead of using serviceType="mediawiki"; you can copy mediawiki.nix to any location outside nixpkgs, modify it at will, and use serviceExpression=./mediawiki.nix; | ||
67 | else if svc ? serviceExpression then import (toString svc.serviceExpression) | ||
68 | else import (toString "${toString ./.}/${if svc ? serviceType then svc.serviceType else svc.serviceName}.nix"); | ||
69 | config = (evalModules | ||
70 | { modules = [ { options = res.options; config = svc.config or svc; } ]; | ||
71 | check = false; | ||
72 | }).config; | ||
73 | defaults = { | ||
74 | extraConfig = ""; | ||
75 | extraModules = []; | ||
76 | extraModulesPre = []; | ||
77 | extraPath = []; | ||
78 | extraServerPath = []; | ||
79 | globalEnvVars = []; | ||
80 | robotsEntries = ""; | ||
81 | startupScript = ""; | ||
82 | enablePHP = false; | ||
83 | enablePerl = false; | ||
84 | phpOptions = ""; | ||
85 | options = {}; | ||
86 | documentRoot = null; | ||
87 | }; | ||
88 | res = defaults // svcFunction { inherit config lib pkgs serverInfo php; }; | ||
89 | in res; | ||
90 | in map f defs; | ||
91 | |||
92 | |||
93 | # !!! callSubservices is expensive | ||
94 | subservicesFor = cfg: callSubservices (makeServerInfo cfg) cfg.extraSubservices; | ||
95 | |||
96 | mainSubservices = subservicesFor mainCfg; | ||
97 | |||
98 | allSubservices = mainSubservices ++ concatMap subservicesFor mainCfg.virtualHosts; | ||
99 | |||
100 | |||
101 | enableSSL = any (vhost: vhost.enableSSL) allHosts; | ||
102 | |||
103 | |||
104 | # Names of modules from ${httpd}/modules that we want to load. | ||
105 | apacheModules = | ||
106 | [ # HTTP authentication mechanisms: basic and digest. | ||
107 | "auth_basic" "auth_digest" | ||
108 | |||
109 | # Authentication: is the user who he claims to be? | ||
110 | "authn_file" "authn_dbm" "authn_anon" | ||
111 | (if version24 then "authn_core" else "authn_alias") | ||
112 | |||
113 | # Authorization: is the user allowed access? | ||
114 | "authz_user" "authz_groupfile" "authz_host" | ||
115 | |||
116 | # Other modules. | ||
117 | "ext_filter" "include" "log_config" "env" "mime_magic" | ||
118 | "cern_meta" "expires" "headers" "usertrack" /* "unique_id" */ "setenvif" | ||
119 | "mime" "dav" "status" "autoindex" "asis" "info" "dav_fs" | ||
120 | "vhost_alias" "negotiation" "dir" "imagemap" "actions" "speling" | ||
121 | "userdir" "alias" "rewrite" "proxy" "proxy_http" | ||
122 | ] | ||
123 | ++ optionals version24 [ | ||
124 | "mpm_${mainCfg.multiProcessingModule}" | ||
125 | "authz_core" | ||
126 | "unixd" | ||
127 | "cache" "cache_disk" | ||
128 | "slotmem_shm" | ||
129 | "socache_shmcb" | ||
130 | # For compatibility with old configurations, the new module mod_access_compat is provided. | ||
131 | "access_compat" | ||
132 | ] | ||
133 | ++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ]) | ||
134 | ++ optional enableSSL "ssl" | ||
135 | ++ extraApacheModules; | ||
136 | |||
137 | |||
138 | allDenied = if version24 then '' | ||
139 | Require all denied | ||
140 | '' else '' | ||
141 | Order deny,allow | ||
142 | Deny from all | ||
143 | ''; | ||
144 | |||
145 | allGranted = if version24 then '' | ||
146 | Require all granted | ||
147 | '' else '' | ||
148 | Order allow,deny | ||
149 | Allow from all | ||
150 | ''; | ||
151 | |||
152 | |||
153 | loggingConf = (if mainCfg.logFormat != "none" then '' | ||
154 | ErrorLog ${mainCfg.logDir}/error_log | ||
155 | |||
156 | LogLevel notice | ||
157 | |||
158 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined | ||
159 | LogFormat "%h %l %u %t \"%r\" %>s %b" common | ||
160 | LogFormat "%{Referer}i -> %U" referer | ||
161 | LogFormat "%{User-agent}i" agent | ||
162 | |||
163 | CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat} | ||
164 | '' else '' | ||
165 | ErrorLog /dev/null | ||
166 | ''); | ||
167 | |||
168 | |||
169 | browserHacks = '' | ||
170 | BrowserMatch "Mozilla/2" nokeepalive | ||
171 | BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 | ||
172 | BrowserMatch "RealPlayer 4\.0" force-response-1.0 | ||
173 | BrowserMatch "Java/1\.0" force-response-1.0 | ||
174 | BrowserMatch "JDK/1\.0" force-response-1.0 | ||
175 | BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully | ||
176 | BrowserMatch "^WebDrive" redirect-carefully | ||
177 | BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully | ||
178 | BrowserMatch "^gnome-vfs" redirect-carefully | ||
179 | ''; | ||
180 | |||
181 | |||
182 | sslConf = '' | ||
183 | SSLSessionCache ${if version24 then "shmcb" else "shm"}:${mainCfg.stateDir}/ssl_scache(512000) | ||
184 | |||
185 | ${if version24 then "Mutex" else "SSLMutex"} posixsem | ||
186 | |||
187 | SSLRandomSeed startup builtin | ||
188 | SSLRandomSeed connect builtin | ||
189 | |||
190 | SSLProtocol All -SSLv2 -SSLv3 | ||
191 | SSLCipherSuite HIGH:!aNULL:!MD5:!EXP | ||
192 | SSLHonorCipherOrder on | ||
193 | ''; | ||
194 | |||
195 | |||
196 | mimeConf = '' | ||
197 | TypesConfig ${httpd}/conf/mime.types | ||
198 | |||
199 | AddType application/x-x509-ca-cert .crt | ||
200 | AddType application/x-pkcs7-crl .crl | ||
201 | AddType application/x-httpd-php .php .phtml | ||
202 | |||
203 | <IfModule mod_mime_magic.c> | ||
204 | MIMEMagicFile ${httpd}/conf/magic | ||
205 | </IfModule> | ||
206 | ''; | ||
207 | |||
208 | |||
209 | perServerConf = isMainServer: cfg: let | ||
210 | |||
211 | serverInfo = makeServerInfo cfg; | ||
212 | |||
213 | subservices = callSubservices serverInfo cfg.extraSubservices; | ||
214 | |||
215 | maybeDocumentRoot = fold (svc: acc: | ||
216 | if acc == null then svc.documentRoot else assert svc.documentRoot == null; acc | ||
217 | ) null ([ cfg ] ++ subservices); | ||
218 | |||
219 | documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else | ||
220 | pkgs.runCommand "empty" {} "mkdir -p $out"; | ||
221 | |||
222 | documentRootConf = '' | ||
223 | DocumentRoot "${documentRoot}" | ||
224 | |||
225 | <Directory "${documentRoot}"> | ||
226 | Options Indexes FollowSymLinks | ||
227 | AllowOverride None | ||
228 | ${allGranted} | ||
229 | </Directory> | ||
230 | ''; | ||
231 | |||
232 | robotsTxt = | ||
233 | concatStringsSep "\n" (filter (x: x != "") ( | ||
234 | # If this is a vhost, the include the entries for the main server as well. | ||
235 | (if isMainServer then [] else [mainCfg.robotsEntries] ++ map (svc: svc.robotsEntries) mainSubservices) | ||
236 | ++ [cfg.robotsEntries] | ||
237 | ++ (map (svc: svc.robotsEntries) subservices))); | ||
238 | |||
239 | in '' | ||
240 | ${concatStringsSep "\n" (map (n: "ServerName ${n}") serverInfo.canonicalNames)} | ||
241 | |||
242 | ${concatMapStrings (alias: "ServerAlias ${alias}\n") cfg.serverAliases} | ||
243 | |||
244 | ${if cfg.sslServerCert != null then '' | ||
245 | SSLCertificateFile ${cfg.sslServerCert} | ||
246 | SSLCertificateKeyFile ${cfg.sslServerKey} | ||
247 | ${if cfg.sslServerChain != null then '' | ||
248 | SSLCertificateChainFile ${cfg.sslServerChain} | ||
249 | '' else ""} | ||
250 | '' else ""} | ||
251 | |||
252 | ${if cfg.enableSSL then '' | ||
253 | SSLEngine on | ||
254 | '' else if enableSSL then /* i.e., SSL is enabled for some host, but not this one */ | ||
255 | '' | ||
256 | SSLEngine off | ||
257 | '' else ""} | ||
258 | |||
259 | ${if isMainServer || cfg.adminAddr != null then '' | ||
260 | ServerAdmin ${cfg.adminAddr} | ||
261 | '' else ""} | ||
262 | |||
263 | ${if !isMainServer && mainCfg.logPerVirtualHost then '' | ||
264 | ErrorLog ${mainCfg.logDir}/error_log-${cfg.hostName} | ||
265 | CustomLog ${mainCfg.logDir}/access_log-${cfg.hostName} ${cfg.logFormat} | ||
266 | '' else ""} | ||
267 | |||
268 | ${optionalString (robotsTxt != "") '' | ||
269 | Alias /robots.txt ${pkgs.writeText "robots.txt" robotsTxt} | ||
270 | ''} | ||
271 | |||
272 | ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""} | ||
273 | |||
274 | ${if cfg.enableUserDir then '' | ||
275 | |||
276 | UserDir public_html | ||
277 | UserDir disabled root | ||
278 | |||
279 | <Directory "/home/*/public_html"> | ||
280 | AllowOverride FileInfo AuthConfig Limit Indexes | ||
281 | Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec | ||
282 | <Limit GET POST OPTIONS> | ||
283 | ${allGranted} | ||
284 | </Limit> | ||
285 | <LimitExcept GET POST OPTIONS> | ||
286 | ${allDenied} | ||
287 | </LimitExcept> | ||
288 | </Directory> | ||
289 | |||
290 | '' else ""} | ||
291 | |||
292 | ${if cfg.globalRedirect != null && cfg.globalRedirect != "" then '' | ||
293 | RedirectPermanent / ${cfg.globalRedirect} | ||
294 | '' else ""} | ||
295 | |||
296 | ${ | ||
297 | let makeFileConf = elem: '' | ||
298 | Alias ${elem.urlPath} ${elem.file} | ||
299 | ''; | ||
300 | in concatMapStrings makeFileConf cfg.servedFiles | ||
301 | } | ||
302 | |||
303 | ${ | ||
304 | let makeDirConf = elem: '' | ||
305 | Alias ${elem.urlPath} ${elem.dir}/ | ||
306 | <Directory ${elem.dir}> | ||
307 | Options +Indexes | ||
308 | ${allGranted} | ||
309 | AllowOverride All | ||
310 | </Directory> | ||
311 | ''; | ||
312 | in concatMapStrings makeDirConf cfg.servedDirs | ||
313 | } | ||
314 | |||
315 | ${concatMapStrings (svc: svc.extraConfig) subservices} | ||
316 | |||
317 | ${cfg.extraConfig} | ||
318 | ''; | ||
319 | |||
320 | |||
321 | confFile = pkgs.writeText "httpd.conf" '' | ||
322 | |||
323 | ServerRoot ${httpd} | ||
324 | |||
325 | ${optionalString version24 '' | ||
326 | DefaultRuntimeDir ${mainCfg.stateDir}/runtime | ||
327 | ''} | ||
328 | |||
329 | PidFile ${mainCfg.stateDir}/httpd.pid | ||
330 | |||
331 | ${optionalString (mainCfg.multiProcessingModule != "prefork") '' | ||
332 | # mod_cgid requires this. | ||
333 | ScriptSock ${mainCfg.stateDir}/cgisock | ||
334 | ''} | ||
335 | |||
336 | <IfModule prefork.c> | ||
337 | MaxClients ${toString mainCfg.maxClients} | ||
338 | MaxRequestsPerChild ${toString mainCfg.maxRequestsPerChild} | ||
339 | </IfModule> | ||
340 | |||
341 | ${let | ||
342 | listen = concatMap getListen allHosts; | ||
343 | toStr = listen: "Listen ${listenToString listen}\n"; | ||
344 | uniqueListen = uniqList {inputList = map toStr listen;}; | ||
345 | in concatStrings uniqueListen | ||
346 | } | ||
347 | |||
348 | User ${mainCfg.user} | ||
349 | Group ${mainCfg.group} | ||
350 | |||
351 | ${let | ||
352 | load = {name, path}: "LoadModule ${name}_module ${path}\n"; | ||
353 | allModules = | ||
354 | concatMap (svc: svc.extraModulesPre) allSubservices | ||
355 | ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules | ||
356 | ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; } | ||
357 | ++ optional enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; } | ||
358 | ++ optional enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; } | ||
359 | ++ concatMap (svc: svc.extraModules) allSubservices | ||
360 | ++ extraForeignModules; | ||
361 | in concatMapStrings load allModules | ||
362 | } | ||
363 | |||
364 | AddHandler type-map var | ||
365 | |||
366 | <Files ~ "^\.ht"> | ||
367 | ${allDenied} | ||
368 | </Files> | ||
369 | |||
370 | ${mimeConf} | ||
371 | ${loggingConf} | ||
372 | ${browserHacks} | ||
373 | |||
374 | Include ${httpd}/conf/extra/httpd-default.conf | ||
375 | Include ${httpd}/conf/extra/httpd-autoindex.conf | ||
376 | Include ${httpd}/conf/extra/httpd-multilang-errordoc.conf | ||
377 | Include ${httpd}/conf/extra/httpd-languages.conf | ||
378 | |||
379 | ${if enableSSL then sslConf else ""} | ||
380 | |||
381 | # Fascist default - deny access to everything. | ||
382 | <Directory /> | ||
383 | Options FollowSymLinks | ||
384 | AllowOverride None | ||
385 | ${allDenied} | ||
386 | </Directory> | ||
387 | |||
388 | # Generate directives for the main server. | ||
389 | ${perServerConf true mainCfg} | ||
390 | |||
391 | # Always enable virtual hosts; it doesn't seem to hurt. | ||
392 | ${let | ||
393 | listen = concatMap getListen allHosts; | ||
394 | uniqueListen = uniqList {inputList = listen;}; | ||
395 | directives = concatMapStrings (listen: "NameVirtualHost ${listenToString listen}\n") uniqueListen; | ||
396 | in optionalString (!version24) directives | ||
397 | } | ||
398 | |||
399 | ${let | ||
400 | makeVirtualHost = vhost: '' | ||
401 | <VirtualHost ${concatStringsSep " " (map listenToString (getListen vhost))}> | ||
402 | ${perServerConf false vhost} | ||
403 | </VirtualHost> | ||
404 | ''; | ||
405 | in concatMapStrings makeVirtualHost mainCfg.virtualHosts | ||
406 | } | ||
407 | ''; | ||
408 | |||
409 | |||
410 | enablePHP = mainCfg.enablePHP || any (svc: svc.enablePHP) allSubservices; | ||
411 | |||
412 | enablePerl = mainCfg.enablePerl || any (svc: svc.enablePerl) allSubservices; | ||
413 | |||
414 | |||
415 | # Generate the PHP configuration file. Should probably be factored | ||
416 | # out into a separate module. | ||
417 | phpIni = pkgs.runCommand "php.ini" | ||
418 | { options = concatStringsSep "\n" | ||
419 | ([ mainCfg.phpOptions ] ++ (map (svc: svc.phpOptions) allSubservices)); | ||
420 | } | ||
421 | '' | ||
422 | cat ${php}/etc/php.ini > $out | ||
423 | echo "$options" >> $out | ||
424 | ''; | ||
425 | |||
426 | in | ||
427 | |||
428 | |||
429 | { | ||
430 | |||
431 | ###### interface | ||
432 | |||
433 | options = { | ||
434 | |||
435 | services.httpdProd = { | ||
436 | |||
437 | enable = mkOption { | ||
438 | type = types.bool; | ||
439 | default = false; | ||
440 | description = "Whether to enable the Apache HTTP Server."; | ||
441 | }; | ||
442 | |||
443 | package = mkOption { | ||
444 | type = types.package; | ||
445 | default = pkgs.apacheHttpd; | ||
446 | defaultText = "pkgs.apacheHttpd"; | ||
447 | description = '' | ||
448 | Overridable attribute of the Apache HTTP Server package to use. | ||
449 | ''; | ||
450 | }; | ||
451 | |||
452 | configFile = mkOption { | ||
453 | type = types.path; | ||
454 | default = confFile; | ||
455 | defaultText = "confFile"; | ||
456 | example = literalExample ''pkgs.writeText "httpd.conf" "# my custom config file ..."''; | ||
457 | description = '' | ||
458 | Override the configuration file used by Apache. By default, | ||
459 | NixOS generates one automatically. | ||
460 | ''; | ||
461 | }; | ||
462 | |||
463 | extraConfig = mkOption { | ||
464 | type = types.lines; | ||
465 | default = ""; | ||
466 | description = '' | ||
467 | Cnfiguration lines appended to the generated Apache | ||
468 | configuration file. Note that this mechanism may not work | ||
469 | when <option>configFile</option> is overridden. | ||
470 | ''; | ||
471 | }; | ||
472 | |||
473 | extraModules = mkOption { | ||
474 | type = types.listOf types.unspecified; | ||
475 | default = []; | ||
476 | example = literalExample ''[ "proxy_connect" { name = "php5"; path = "''${pkgs.php}/modules/libphp5.so"; } ]''; | ||
477 | description = '' | ||
478 | Additional Apache modules to be used. These can be | ||
479 | specified as a string in the case of modules distributed | ||
480 | with Apache, or as an attribute set specifying the | ||
481 | <varname>name</varname> and <varname>path</varname> of the | ||
482 | module. | ||
483 | ''; | ||
484 | }; | ||
485 | |||
486 | logPerVirtualHost = mkOption { | ||
487 | type = types.bool; | ||
488 | default = false; | ||
489 | description = '' | ||
490 | If enabled, each virtual host gets its own | ||
491 | <filename>access_log</filename> and | ||
492 | <filename>error_log</filename>, namely suffixed by the | ||
493 | <option>hostName</option> of the virtual host. | ||
494 | ''; | ||
495 | }; | ||
496 | |||
497 | user = mkOption { | ||
498 | type = types.str; | ||
499 | default = "wwwrun"; | ||
500 | description = '' | ||
501 | User account under which httpd runs. The account is created | ||
502 | automatically if it doesn't exist. | ||
503 | ''; | ||
504 | }; | ||
505 | |||
506 | group = mkOption { | ||
507 | type = types.str; | ||
508 | default = "wwwrun"; | ||
509 | description = '' | ||
510 | Group under which httpd runs. The account is created | ||
511 | automatically if it doesn't exist. | ||
512 | ''; | ||
513 | }; | ||
514 | |||
515 | logDir = mkOption { | ||
516 | type = types.path; | ||
517 | default = "/var/log/httpd"; | ||
518 | description = '' | ||
519 | Directory for Apache's log files. It is created automatically. | ||
520 | ''; | ||
521 | }; | ||
522 | |||
523 | stateDir = mkOption { | ||
524 | type = types.path; | ||
525 | default = "/run/httpd"; | ||
526 | description = '' | ||
527 | Directory for Apache's transient runtime state (such as PID | ||
528 | files). It is created automatically. Note that the default, | ||
529 | <filename>/run/httpd</filename>, is deleted at boot time. | ||
530 | ''; | ||
531 | }; | ||
532 | |||
533 | virtualHosts = mkOption { | ||
534 | type = types.listOf (types.submodule ( | ||
535 | { options = import ./per-server-options.nix { | ||
536 | inherit lib; | ||
537 | forMainServer = false; | ||
538 | }; | ||
539 | })); | ||
540 | default = []; | ||
541 | example = [ | ||
542 | { hostName = "foo"; | ||
543 | documentRoot = "/data/webroot-foo"; | ||
544 | } | ||
545 | { hostName = "bar"; | ||
546 | documentRoot = "/data/webroot-bar"; | ||
547 | } | ||
548 | ]; | ||
549 | description = '' | ||
550 | Specification of the virtual hosts served by Apache. Each | ||
551 | element should be an attribute set specifying the | ||
552 | configuration of the virtual host. The available options | ||
553 | are the non-global options permissible for the main host. | ||
554 | ''; | ||
555 | }; | ||
556 | |||
557 | enableMellon = mkOption { | ||
558 | type = types.bool; | ||
559 | default = false; | ||
560 | description = "Whether to enable the mod_auth_mellon module."; | ||
561 | }; | ||
562 | |||
563 | enablePHP = mkOption { | ||
564 | type = types.bool; | ||
565 | default = false; | ||
566 | description = "Whether to enable the PHP module."; | ||
567 | }; | ||
568 | |||
569 | phpPackage = mkOption { | ||
570 | type = types.package; | ||
571 | default = pkgs.php; | ||
572 | defaultText = "pkgs.php"; | ||
573 | description = '' | ||
574 | Overridable attribute of the PHP package to use. | ||
575 | ''; | ||
576 | }; | ||
577 | |||
578 | enablePerl = mkOption { | ||
579 | type = types.bool; | ||
580 | default = false; | ||
581 | description = "Whether to enable the Perl module (mod_perl)."; | ||
582 | }; | ||
583 | |||
584 | phpOptions = mkOption { | ||
585 | type = types.lines; | ||
586 | default = ""; | ||
587 | example = | ||
588 | '' | ||
589 | date.timezone = "CET" | ||
590 | ''; | ||
591 | description = | ||
592 | "Options appended to the PHP configuration file <filename>php.ini</filename>."; | ||
593 | }; | ||
594 | |||
595 | multiProcessingModule = mkOption { | ||
596 | type = types.str; | ||
597 | default = "prefork"; | ||
598 | example = "worker"; | ||
599 | description = | ||
600 | '' | ||
601 | Multi-processing module to be used by Apache. Available | ||
602 | modules are <literal>prefork</literal> (the default; | ||
603 | handles each request in a separate child process), | ||
604 | <literal>worker</literal> (hybrid approach that starts a | ||
605 | number of child processes each running a number of | ||
606 | threads) and <literal>event</literal> (a recent variant of | ||
607 | <literal>worker</literal> that handles persistent | ||
608 | connections more efficiently). | ||
609 | ''; | ||
610 | }; | ||
611 | |||
612 | maxClients = mkOption { | ||
613 | type = types.int; | ||
614 | default = 150; | ||
615 | example = 8; | ||
616 | description = "Maximum number of httpd processes (prefork)"; | ||
617 | }; | ||
618 | |||
619 | maxRequestsPerChild = mkOption { | ||
620 | type = types.int; | ||
621 | default = 0; | ||
622 | example = 500; | ||
623 | description = | ||
624 | "Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited"; | ||
625 | }; | ||
626 | } | ||
627 | |||
628 | # Include the options shared between the main server and virtual hosts. | ||
629 | // (import ./per-server-options.nix { | ||
630 | inherit lib; | ||
631 | forMainServer = true; | ||
632 | }); | ||
633 | |||
634 | }; | ||
635 | |||
636 | |||
637 | ###### implementation | ||
638 | |||
639 | config = mkIf config.services.httpdProd.enable { | ||
640 | |||
641 | assertions = [ { assertion = mainCfg.enableSSL == true | ||
642 | -> mainCfg.sslServerCert != null | ||
643 | && mainCfg.sslServerKey != null; | ||
644 | message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; } | ||
645 | ]; | ||
646 | |||
647 | warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port};}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts); | ||
648 | |||
649 | environment.systemPackages = [httpd] ++ concatMap (svc: svc.extraPath) allSubservices; | ||
650 | |||
651 | services.httpdProd.phpOptions = | ||
652 | '' | ||
653 | ; Needed for PHP's mail() function. | ||
654 | sendmail_path = sendmail -t -i | ||
655 | '' + optionalString (!isNull config.time.timeZone) '' | ||
656 | |||
657 | ; Apparently PHP doesn't use $TZ. | ||
658 | date.timezone = "${config.time.timeZone}" | ||
659 | ''; | ||
660 | |||
661 | systemd.services.httpdProd = | ||
662 | { description = "Apache HTTPD"; | ||
663 | |||
664 | wantedBy = [ "multi-user.target" ]; | ||
665 | wants = [ "keys.target" ]; | ||
666 | after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ]; | ||
667 | |||
668 | path = | ||
669 | [ httpd pkgs.coreutils pkgs.gnugrep ] | ||
670 | ++ # Needed for PHP's mail() function. !!! Probably the | ||
671 | # ssmtp module should export the path to sendmail in | ||
672 | # some way. | ||
673 | optional config.networking.defaultMailServer.directDelivery pkgs.ssmtp | ||
674 | ++ concatMap (svc: svc.extraServerPath) allSubservices; | ||
675 | |||
676 | environment = | ||
677 | optionalAttrs enablePHP { PHPRC = phpIni; } | ||
678 | // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; } | ||
679 | // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices)); | ||
680 | |||
681 | preStart = | ||
682 | '' | ||
683 | mkdir -m 0750 -p ${mainCfg.stateDir} | ||
684 | [ $(id -u) != 0 ] || chown root.${mainCfg.group} ${mainCfg.stateDir} | ||
685 | ${optionalString version24 '' | ||
686 | mkdir -m 0750 -p "${mainCfg.stateDir}/runtime" | ||
687 | [ $(id -u) != 0 ] || chown root.${mainCfg.group} "${mainCfg.stateDir}/runtime" | ||
688 | ''} | ||
689 | mkdir -m 0700 -p ${mainCfg.logDir} | ||
690 | |||
691 | # Get rid of old semaphores. These tend to accumulate across | ||
692 | # server restarts, eventually preventing it from restarting | ||
693 | # successfully. | ||
694 | for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${mainCfg.user} ' | cut -f2 -d ' '); do | ||
695 | ${pkgs.utillinux}/bin/ipcrm -s $i | ||
696 | done | ||
697 | |||
698 | # Run the startup hooks for the subservices. | ||
699 | for i in ${toString (map (svn: svn.startupScript) allSubservices)}; do | ||
700 | echo Running Apache startup hook $i... | ||
701 | $i | ||
702 | done | ||
703 | ''; | ||
704 | |||
705 | serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf}"; | ||
706 | serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop"; | ||
707 | serviceConfig.ExecReload = "${httpd}/bin/httpd -f ${httpdConf} -k graceful"; | ||
708 | serviceConfig.Type = "forking"; | ||
709 | serviceConfig.PIDFile = "${mainCfg.stateDir}/httpd.pid"; | ||
710 | serviceConfig.Restart = "always"; | ||
711 | serviceConfig.RestartSec = "5s"; | ||
712 | }; | ||
713 | |||
714 | }; | ||
715 | } | ||
diff --git a/virtual/modules/websites/apache/httpd_tools.nix b/virtual/modules/websites/apache/httpd_tools.nix deleted file mode 100644 index c0b779b..0000000 --- a/virtual/modules/websites/apache/httpd_tools.nix +++ /dev/null | |||
@@ -1,727 +0,0 @@ | |||
1 | { config, lib, pkgs, ... }: | ||
2 | |||
3 | with lib; | ||
4 | |||
5 | let | ||
6 | |||
7 | mainCfg = config.services.httpdTools; | ||
8 | |||
9 | httpd = mainCfg.package.out; | ||
10 | |||
11 | version24 = !versionOlder httpd.version "2.4"; | ||
12 | |||
13 | httpdConf = mainCfg.configFile; | ||
14 | |||
15 | php = mainCfg.phpPackage.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ }; | ||
16 | |||
17 | phpMajorVersion = head (splitString "." php.version); | ||
18 | |||
19 | mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; }; | ||
20 | |||
21 | defaultListen = cfg: if cfg.enableSSL | ||
22 | then [{ip = "*"; port = 443;}] | ||
23 | else [{ip = "*"; port = 80;}]; | ||
24 | |||
25 | getListen = cfg: | ||
26 | let list = (lib.optional (cfg.port != 0) {ip = "*"; port = cfg.port;}) ++ cfg.listen; | ||
27 | in if list == [] | ||
28 | then defaultListen cfg | ||
29 | else list; | ||
30 | |||
31 | listenToString = l: "${l.ip}:${toString l.port}"; | ||
32 | |||
33 | extraModules = attrByPath ["extraModules"] [] mainCfg; | ||
34 | extraForeignModules = filter isAttrs extraModules; | ||
35 | extraApacheModules = filter isString extraModules; | ||
36 | |||
37 | |||
38 | makeServerInfo = cfg: { | ||
39 | # Canonical name must not include a trailing slash. | ||
40 | canonicalNames = | ||
41 | let defaultPort = (head (defaultListen cfg)).port; in | ||
42 | map (port: | ||
43 | (if cfg.enableSSL then "https" else "http") + "://" + | ||
44 | cfg.hostName + | ||
45 | (if port != defaultPort then ":${toString port}" else "") | ||
46 | ) (map (x: x.port) (getListen cfg)); | ||
47 | |||
48 | # Admin address: inherit from the main server if not specified for | ||
49 | # a virtual host. | ||
50 | adminAddr = if cfg.adminAddr != null then cfg.adminAddr else mainCfg.adminAddr; | ||
51 | |||
52 | vhostConfig = cfg; | ||
53 | serverConfig = mainCfg; | ||
54 | fullConfig = config; # machine config | ||
55 | }; | ||
56 | |||
57 | |||
58 | allHosts = [mainCfg] ++ mainCfg.virtualHosts; | ||
59 | |||
60 | |||
61 | callSubservices = serverInfo: defs: | ||
62 | let f = svc: | ||
63 | let | ||
64 | svcFunction = | ||
65 | if svc ? function then svc.function | ||
66 | # instead of using serviceType="mediawiki"; you can copy mediawiki.nix to any location outside nixpkgs, modify it at will, and use serviceExpression=./mediawiki.nix; | ||
67 | else if svc ? serviceExpression then import (toString svc.serviceExpression) | ||
68 | else import (toString "${toString ./.}/${if svc ? serviceType then svc.serviceType else svc.serviceName}.nix"); | ||
69 | config = (evalModules | ||
70 | { modules = [ { options = res.options; config = svc.config or svc; } ]; | ||
71 | check = false; | ||
72 | }).config; | ||
73 | defaults = { | ||
74 | extraConfig = ""; | ||
75 | extraModules = []; | ||
76 | extraModulesPre = []; | ||
77 | extraPath = []; | ||
78 | extraServerPath = []; | ||
79 | globalEnvVars = []; | ||
80 | robotsEntries = ""; | ||
81 | startupScript = ""; | ||
82 | enablePHP = false; | ||
83 | enablePerl = false; | ||
84 | phpOptions = ""; | ||
85 | options = {}; | ||
86 | documentRoot = null; | ||
87 | }; | ||
88 | res = defaults // svcFunction { inherit config lib pkgs serverInfo php; }; | ||
89 | in res; | ||
90 | in map f defs; | ||
91 | |||
92 | |||
93 | # !!! callSubservices is expensive | ||
94 | subservicesFor = cfg: callSubservices (makeServerInfo cfg) cfg.extraSubservices; | ||
95 | |||
96 | mainSubservices = subservicesFor mainCfg; | ||
97 | |||
98 | allSubservices = mainSubservices ++ concatMap subservicesFor mainCfg.virtualHosts; | ||
99 | |||
100 | |||
101 | enableSSL = any (vhost: vhost.enableSSL) allHosts; | ||
102 | |||
103 | |||
104 | # Names of modules from ${httpd}/modules that we want to load. | ||
105 | apacheModules = | ||
106 | [ # HTTP authentication mechanisms: basic and digest. | ||
107 | "auth_basic" "auth_digest" | ||
108 | |||
109 | # Authentication: is the user who he claims to be? | ||
110 | "authn_file" "authn_dbm" "authn_anon" | ||
111 | (if version24 then "authn_core" else "authn_alias") | ||
112 | |||
113 | # Authorization: is the user allowed access? | ||
114 | "authz_user" "authz_groupfile" "authz_host" | ||
115 | |||
116 | # Other modules. | ||
117 | "ext_filter" "include" "log_config" "env" "mime_magic" | ||
118 | "cern_meta" "expires" "headers" "usertrack" /* "unique_id" */ "setenvif" | ||
119 | "mime" "dav" "status" "autoindex" "asis" "info" "dav_fs" | ||
120 | "vhost_alias" "negotiation" "dir" "imagemap" "actions" "speling" | ||
121 | "userdir" "alias" "rewrite" "proxy" "proxy_http" | ||
122 | ] | ||
123 | ++ optionals version24 [ | ||
124 | "mpm_${mainCfg.multiProcessingModule}" | ||
125 | "authz_core" | ||
126 | "unixd" | ||
127 | "cache" "cache_disk" | ||
128 | "slotmem_shm" | ||
129 | "socache_shmcb" | ||
130 | # For compatibility with old configurations, the new module mod_access_compat is provided. | ||
131 | "access_compat" | ||
132 | ] | ||
133 | ++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ]) | ||
134 | ++ optional enableSSL "ssl" | ||
135 | ++ extraApacheModules; | ||
136 | |||
137 | |||
138 | allDenied = if version24 then '' | ||
139 | Require all denied | ||
140 | '' else '' | ||
141 | Order deny,allow | ||
142 | Deny from all | ||
143 | ''; | ||
144 | |||
145 | allGranted = if version24 then '' | ||
146 | Require all granted | ||
147 | '' else '' | ||
148 | Order allow,deny | ||
149 | Allow from all | ||
150 | ''; | ||
151 | |||
152 | |||
153 | loggingConf = (if mainCfg.logFormat != "none" then '' | ||
154 | ErrorLog ${mainCfg.logDir}/error_log | ||
155 | |||
156 | LogLevel notice | ||
157 | |||
158 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined | ||
159 | LogFormat "%h %l %u %t \"%r\" %>s %b" common | ||
160 | LogFormat "%{Referer}i -> %U" referer | ||
161 | LogFormat "%{User-agent}i" agent | ||
162 | |||
163 | CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat} | ||
164 | '' else '' | ||
165 | ErrorLog /dev/null | ||
166 | ''); | ||
167 | |||
168 | |||
169 | browserHacks = '' | ||
170 | BrowserMatch "Mozilla/2" nokeepalive | ||
171 | BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 | ||
172 | BrowserMatch "RealPlayer 4\.0" force-response-1.0 | ||
173 | BrowserMatch "Java/1\.0" force-response-1.0 | ||
174 | BrowserMatch "JDK/1\.0" force-response-1.0 | ||
175 | BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully | ||
176 | BrowserMatch "^WebDrive" redirect-carefully | ||
177 | BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully | ||
178 | BrowserMatch "^gnome-vfs" redirect-carefully | ||
179 | ''; | ||
180 | |||
181 | |||
182 | sslConf = '' | ||
183 | SSLSessionCache ${if version24 then "shmcb" else "shm"}:${mainCfg.stateDir}/ssl_scache(512000) | ||
184 | |||
185 | ${if version24 then "Mutex" else "SSLMutex"} posixsem | ||
186 | |||
187 | SSLRandomSeed startup builtin | ||
188 | SSLRandomSeed connect builtin | ||
189 | |||
190 | SSLProtocol All -SSLv2 -SSLv3 | ||
191 | SSLCipherSuite HIGH:!aNULL:!MD5:!EXP | ||
192 | SSLHonorCipherOrder on | ||
193 | ''; | ||
194 | |||
195 | |||
196 | mimeConf = '' | ||
197 | TypesConfig ${httpd}/conf/mime.types | ||
198 | |||
199 | AddType application/x-x509-ca-cert .crt | ||
200 | AddType application/x-pkcs7-crl .crl | ||
201 | AddType application/x-httpd-php .php .phtml | ||
202 | |||
203 | <IfModule mod_mime_magic.c> | ||
204 | MIMEMagicFile ${httpd}/conf/magic | ||
205 | </IfModule> | ||
206 | ''; | ||
207 | |||
208 | |||
209 | perServerConf = isMainServer: cfg: let | ||
210 | |||
211 | serverInfo = makeServerInfo cfg; | ||
212 | |||
213 | subservices = callSubservices serverInfo cfg.extraSubservices; | ||
214 | |||
215 | maybeDocumentRoot = fold (svc: acc: | ||
216 | if acc == null then svc.documentRoot else assert svc.documentRoot == null; acc | ||
217 | ) null ([ cfg ] ++ subservices); | ||
218 | |||
219 | documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else | ||
220 | pkgs.runCommand "empty" {} "mkdir -p $out"; | ||
221 | |||
222 | documentRootConf = '' | ||
223 | DocumentRoot "${documentRoot}" | ||
224 | |||
225 | <Directory "${documentRoot}"> | ||
226 | Options Indexes FollowSymLinks | ||
227 | AllowOverride None | ||
228 | ${allGranted} | ||
229 | </Directory> | ||
230 | ''; | ||
231 | |||
232 | robotsTxt = | ||
233 | concatStringsSep "\n" (filter (x: x != "") ( | ||
234 | # If this is a vhost, the include the entries for the main server as well. | ||
235 | (if isMainServer then [] else [mainCfg.robotsEntries] ++ map (svc: svc.robotsEntries) mainSubservices) | ||
236 | ++ [cfg.robotsEntries] | ||
237 | ++ (map (svc: svc.robotsEntries) subservices))); | ||
238 | |||
239 | in '' | ||
240 | ${concatStringsSep "\n" (map (n: "ServerName ${n}") serverInfo.canonicalNames)} | ||
241 | |||
242 | ${concatMapStrings (alias: "ServerAlias ${alias}\n") cfg.serverAliases} | ||
243 | |||
244 | ${if cfg.sslServerCert != null then '' | ||
245 | SSLCertificateFile ${cfg.sslServerCert} | ||
246 | SSLCertificateKeyFile ${cfg.sslServerKey} | ||
247 | ${if cfg.sslServerChain != null then '' | ||
248 | SSLCertificateChainFile ${cfg.sslServerChain} | ||
249 | '' else ""} | ||
250 | '' else ""} | ||
251 | |||
252 | ${if cfg.enableSSL then '' | ||
253 | SSLEngine on | ||
254 | '' else if enableSSL then /* i.e., SSL is enabled for some host, but not this one */ | ||
255 | '' | ||
256 | SSLEngine off | ||
257 | '' else ""} | ||
258 | |||
259 | ${if isMainServer || cfg.adminAddr != null then '' | ||
260 | ServerAdmin ${cfg.adminAddr} | ||
261 | '' else ""} | ||
262 | |||
263 | ${if !isMainServer && mainCfg.logPerVirtualHost then '' | ||
264 | ErrorLog ${mainCfg.logDir}/error_log-${cfg.hostName} | ||
265 | CustomLog ${mainCfg.logDir}/access_log-${cfg.hostName} ${cfg.logFormat} | ||
266 | '' else ""} | ||
267 | |||
268 | ${optionalString (robotsTxt != "") '' | ||
269 | Alias /robots.txt ${pkgs.writeText "robots.txt" robotsTxt} | ||
270 | ''} | ||
271 | |||
272 | ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""} | ||
273 | |||
274 | ${if cfg.enableUserDir then '' | ||
275 | |||
276 | UserDir public_html | ||
277 | UserDir disabled root | ||
278 | |||
279 | <Directory "/home/*/public_html"> | ||
280 | AllowOverride FileInfo AuthConfig Limit Indexes | ||
281 | Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec | ||
282 | <Limit GET POST OPTIONS> | ||
283 | ${allGranted} | ||
284 | </Limit> | ||
285 | <LimitExcept GET POST OPTIONS> | ||
286 | ${allDenied} | ||
287 | </LimitExcept> | ||
288 | </Directory> | ||
289 | |||
290 | '' else ""} | ||
291 | |||
292 | ${if cfg.globalRedirect != null && cfg.globalRedirect != "" then '' | ||
293 | RedirectPermanent / ${cfg.globalRedirect} | ||
294 | '' else ""} | ||
295 | |||
296 | ${ | ||
297 | let makeFileConf = elem: '' | ||
298 | Alias ${elem.urlPath} ${elem.file} | ||
299 | ''; | ||
300 | in concatMapStrings makeFileConf cfg.servedFiles | ||
301 | } | ||
302 | |||
303 | ${ | ||
304 | let makeDirConf = elem: '' | ||
305 | Alias ${elem.urlPath} ${elem.dir}/ | ||
306 | <Directory ${elem.dir}> | ||
307 | Options +Indexes | ||
308 | ${allGranted} | ||
309 | AllowOverride All | ||
310 | </Directory> | ||
311 | ''; | ||
312 | in concatMapStrings makeDirConf cfg.servedDirs | ||
313 | } | ||
314 | |||
315 | ${concatMapStrings (svc: svc.extraConfig) subservices} | ||
316 | |||
317 | ${cfg.extraConfig} | ||
318 | ''; | ||
319 | |||
320 | |||
321 | confFile = pkgs.writeText "httpd.conf" '' | ||
322 | |||
323 | ServerRoot ${httpd} | ||
324 | |||
325 | ${optionalString version24 '' | ||
326 | DefaultRuntimeDir ${mainCfg.stateDir}/runtime | ||
327 | ''} | ||
328 | |||
329 | PidFile ${mainCfg.stateDir}/httpd.pid | ||
330 | |||
331 | ${optionalString (mainCfg.multiProcessingModule != "prefork") '' | ||
332 | # mod_cgid requires this. | ||
333 | ScriptSock ${mainCfg.stateDir}/cgisock | ||
334 | ''} | ||
335 | |||
336 | <IfModule prefork.c> | ||
337 | MaxClients ${toString mainCfg.maxClients} | ||
338 | MaxRequestsPerChild ${toString mainCfg.maxRequestsPerChild} | ||
339 | </IfModule> | ||
340 | |||
341 | ${let | ||
342 | listen = concatMap getListen allHosts; | ||
343 | toStr = listen: "Listen ${listenToString listen}\n"; | ||
344 | uniqueListen = uniqList {inputList = map toStr listen;}; | ||
345 | in concatStrings uniqueListen | ||
346 | } | ||
347 | |||
348 | User ${mainCfg.user} | ||
349 | Group ${mainCfg.group} | ||
350 | |||
351 | ${let | ||
352 | load = {name, path}: "LoadModule ${name}_module ${path}\n"; | ||
353 | allModules = | ||
354 | concatMap (svc: svc.extraModulesPre) allSubservices | ||
355 | ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules | ||
356 | ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; } | ||
357 | ++ optional enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; } | ||
358 | ++ optional enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; } | ||
359 | ++ concatMap (svc: svc.extraModules) allSubservices | ||
360 | ++ extraForeignModules; | ||
361 | in concatMapStrings load allModules | ||
362 | } | ||
363 | |||
364 | AddHandler type-map var | ||
365 | |||
366 | <Files ~ "^\.ht"> | ||
367 | ${allDenied} | ||
368 | </Files> | ||
369 | |||
370 | ${mimeConf} | ||
371 | ${loggingConf} | ||
372 | ${browserHacks} | ||
373 | |||
374 | Include ${httpd}/conf/extra/httpd-default.conf | ||
375 | Include ${httpd}/conf/extra/httpd-autoindex.conf | ||
376 | Include ${httpd}/conf/extra/httpd-multilang-errordoc.conf | ||
377 | Include ${httpd}/conf/extra/httpd-languages.conf | ||
378 | |||
379 | ${if enableSSL then sslConf else ""} | ||
380 | |||
381 | # Fascist default - deny access to everything. | ||
382 | <Directory /> | ||
383 | Options FollowSymLinks | ||
384 | AllowOverride None | ||
385 | ${allDenied} | ||
386 | </Directory> | ||
387 | |||
388 | # Generate directives for the main server. | ||
389 | ${perServerConf true mainCfg} | ||
390 | |||
391 | # Always enable virtual hosts; it doesn't seem to hurt. | ||
392 | ${let | ||
393 | listen = concatMap getListen allHosts; | ||
394 | uniqueListen = uniqList {inputList = listen;}; | ||
395 | directives = concatMapStrings (listen: "NameVirtualHost ${listenToString listen}\n") uniqueListen; | ||
396 | in optionalString (!version24) directives | ||
397 | } | ||
398 | |||
399 | ${let | ||
400 | makeVirtualHost = vhost: '' | ||
401 | <VirtualHost ${concatStringsSep " " (map listenToString (getListen vhost))}> | ||
402 | ${perServerConf false vhost} | ||
403 | </VirtualHost> | ||
404 | ''; | ||
405 | in concatMapStrings makeVirtualHost mainCfg.virtualHosts | ||
406 | } | ||
407 | ''; | ||
408 | |||
409 | |||
410 | enablePHP = mainCfg.enablePHP || any (svc: svc.enablePHP) allSubservices; | ||
411 | |||
412 | enablePerl = mainCfg.enablePerl || any (svc: svc.enablePerl) allSubservices; | ||
413 | |||
414 | |||
415 | # Generate the PHP configuration file. Should probably be factored | ||
416 | # out into a separate module. | ||
417 | phpIni = pkgs.runCommand "php.ini" | ||
418 | { options = concatStringsSep "\n" | ||
419 | ([ mainCfg.phpOptions ] ++ (map (svc: svc.phpOptions) allSubservices)); | ||
420 | } | ||
421 | '' | ||
422 | cat ${php}/etc/php.ini > $out | ||
423 | echo "$options" >> $out | ||
424 | ''; | ||
425 | |||
426 | in | ||
427 | |||
428 | |||
429 | { | ||
430 | |||
431 | ###### interface | ||
432 | |||
433 | options = { | ||
434 | |||
435 | services.httpdTools = { | ||
436 | |||
437 | enable = mkOption { | ||
438 | type = types.bool; | ||
439 | default = false; | ||
440 | description = "Whether to enable the Apache HTTP Server."; | ||
441 | }; | ||
442 | |||
443 | package = mkOption { | ||
444 | type = types.package; | ||
445 | default = pkgs.apacheHttpd; | ||
446 | defaultText = "pkgs.apacheHttpd"; | ||
447 | description = '' | ||
448 | Overridable attribute of the Apache HTTP Server package to use. | ||
449 | ''; | ||
450 | }; | ||
451 | |||
452 | configFile = mkOption { | ||
453 | type = types.path; | ||
454 | default = confFile; | ||
455 | defaultText = "confFile"; | ||
456 | example = literalExample ''pkgs.writeText "httpd.conf" "# my custom config file ..."''; | ||
457 | description = '' | ||
458 | Override the configuration file used by Apache. By default, | ||
459 | NixOS generates one automatically. | ||
460 | ''; | ||
461 | }; | ||
462 | |||
463 | extraConfig = mkOption { | ||
464 | type = types.lines; | ||
465 | default = ""; | ||
466 | description = '' | ||
467 | Cnfiguration lines appended to the generated Apache | ||
468 | configuration file. Note that this mechanism may not work | ||
469 | when <option>configFile</option> is overridden. | ||
470 | ''; | ||
471 | }; | ||
472 | |||
473 | extraModules = mkOption { | ||
474 | type = types.listOf types.unspecified; | ||
475 | default = []; | ||
476 | example = literalExample ''[ "proxy_connect" { name = "php5"; path = "''${pkgs.php}/modules/libphp5.so"; } ]''; | ||
477 | description = '' | ||
478 | Additional Apache modules to be used. These can be | ||
479 | specified as a string in the case of modules distributed | ||
480 | with Apache, or as an attribute set specifying the | ||
481 | <varname>name</varname> and <varname>path</varname> of the | ||
482 | module. | ||
483 | ''; | ||
484 | }; | ||
485 | |||
486 | logPerVirtualHost = mkOption { | ||
487 | type = types.bool; | ||
488 | default = false; | ||
489 | description = '' | ||
490 | If enabled, each virtual host gets its own | ||
491 | <filename>access_log</filename> and | ||
492 | <filename>error_log</filename>, namely suffixed by the | ||
493 | <option>hostName</option> of the virtual host. | ||
494 | ''; | ||
495 | }; | ||
496 | |||
497 | user = mkOption { | ||
498 | type = types.str; | ||
499 | default = "wwwrun"; | ||
500 | description = '' | ||
501 | User account under which httpd runs. The account is created | ||
502 | automatically if it doesn't exist. | ||
503 | ''; | ||
504 | }; | ||
505 | |||
506 | group = mkOption { | ||
507 | type = types.str; | ||
508 | default = "wwwrun"; | ||
509 | description = '' | ||
510 | Group under which httpd runs. The account is created | ||
511 | automatically if it doesn't exist. | ||
512 | ''; | ||
513 | }; | ||
514 | |||
515 | logDir = mkOption { | ||
516 | type = types.path; | ||
517 | default = "/var/log/httpd"; | ||
518 | description = '' | ||
519 | Directory for Apache's log files. It is created automatically. | ||
520 | ''; | ||
521 | }; | ||
522 | |||
523 | stateDir = mkOption { | ||
524 | type = types.path; | ||
525 | default = "/run/httpd"; | ||
526 | description = '' | ||
527 | Directory for Apache's transient runtime state (such as PID | ||
528 | files). It is created automatically. Note that the default, | ||
529 | <filename>/run/httpd</filename>, is deleted at boot time. | ||
530 | ''; | ||
531 | }; | ||
532 | |||
533 | virtualHosts = mkOption { | ||
534 | type = types.listOf (types.submodule ( | ||
535 | { options = import ./per-server-options.nix { | ||
536 | inherit lib; | ||
537 | forMainServer = false; | ||
538 | }; | ||
539 | })); | ||
540 | default = []; | ||
541 | example = [ | ||
542 | { hostName = "foo"; | ||
543 | documentRoot = "/data/webroot-foo"; | ||
544 | } | ||
545 | { hostName = "bar"; | ||
546 | documentRoot = "/data/webroot-bar"; | ||
547 | } | ||
548 | ]; | ||
549 | description = '' | ||
550 | Specification of the virtual hosts served by Apache. Each | ||
551 | element should be an attribute set specifying the | ||
552 | configuration of the virtual host. The available options | ||
553 | are the non-global options permissible for the main host. | ||
554 | ''; | ||
555 | }; | ||
556 | |||
557 | enableMellon = mkOption { | ||
558 | type = types.bool; | ||
559 | default = false; | ||
560 | description = "Whether to enable the mod_auth_mellon module."; | ||
561 | }; | ||
562 | |||
563 | enablePHP = mkOption { | ||
564 | type = types.bool; | ||
565 | default = false; | ||
566 | description = "Whether to enable the PHP module."; | ||
567 | }; | ||
568 | |||
569 | phpPackage = mkOption { | ||
570 | type = types.package; | ||
571 | default = pkgs.php; | ||
572 | defaultText = "pkgs.php"; | ||
573 | description = '' | ||
574 | Overridable attribute of the PHP package to use. | ||
575 | ''; | ||
576 | }; | ||
577 | |||
578 | enablePerl = mkOption { | ||
579 | type = types.bool; | ||
580 | default = false; | ||
581 | description = "Whether to enable the Perl module (mod_perl)."; | ||
582 | }; | ||
583 | |||
584 | phpOptions = mkOption { | ||
585 | type = types.lines; | ||
586 | default = ""; | ||
587 | example = | ||
588 | '' | ||
589 | date.timezone = "CET" | ||
590 | ''; | ||
591 | description = | ||
592 | "Options appended to the PHP configuration file <filename>php.ini</filename>."; | ||
593 | }; | ||
594 | |||
595 | multiProcessingModule = mkOption { | ||
596 | type = types.str; | ||
597 | default = "prefork"; | ||
598 | example = "worker"; | ||
599 | description = | ||
600 | '' | ||
601 | Multi-processing module to be used by Apache. Available | ||
602 | modules are <literal>prefork</literal> (the default; | ||
603 | handles each request in a separate child process), | ||
604 | <literal>worker</literal> (hybrid approach that starts a | ||
605 | number of child processes each running a number of | ||
606 | threads) and <literal>event</literal> (a recent variant of | ||
607 | <literal>worker</literal> that handles persistent | ||
608 | connections more efficiently). | ||
609 | ''; | ||
610 | }; | ||
611 | |||
612 | maxClients = mkOption { | ||
613 | type = types.int; | ||
614 | default = 150; | ||
615 | example = 8; | ||
616 | description = "Maximum number of httpd processes (prefork)"; | ||
617 | }; | ||
618 | |||
619 | maxRequestsPerChild = mkOption { | ||
620 | type = types.int; | ||
621 | default = 0; | ||
622 | example = 500; | ||
623 | description = | ||
624 | "Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited"; | ||
625 | }; | ||
626 | } | ||
627 | |||
628 | # Include the options shared between the main server and virtual hosts. | ||
629 | // (import ./per-server-options.nix { | ||
630 | inherit lib; | ||
631 | forMainServer = true; | ||
632 | }); | ||
633 | |||
634 | }; | ||
635 | |||
636 | |||
637 | ###### implementation | ||
638 | |||
639 | config = mkIf config.services.httpdTools.enable { | ||
640 | |||
641 | assertions = [ { assertion = mainCfg.enableSSL == true | ||
642 | -> mainCfg.sslServerCert != null | ||
643 | && mainCfg.sslServerKey != null; | ||
644 | message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; } | ||
645 | ]; | ||
646 | |||
647 | warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port};}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts); | ||
648 | |||
649 | users.users = optionalAttrs (mainCfg.user == "wwwrun") (singleton | ||
650 | { name = "wwwrun"; | ||
651 | group = mainCfg.group; | ||
652 | description = "Apache httpd user"; | ||
653 | uid = config.ids.uids.wwwrun; | ||
654 | }); | ||
655 | |||
656 | users.groups = optionalAttrs (mainCfg.group == "wwwrun") (singleton | ||
657 | { name = "wwwrun"; | ||
658 | gid = config.ids.gids.wwwrun; | ||
659 | }); | ||
660 | |||
661 | environment.systemPackages = [httpd] ++ concatMap (svc: svc.extraPath) allSubservices; | ||
662 | |||
663 | services.httpdTools.phpOptions = | ||
664 | '' | ||
665 | ; Needed for PHP's mail() function. | ||
666 | sendmail_path = sendmail -t -i | ||
667 | '' + optionalString (!isNull config.time.timeZone) '' | ||
668 | |||
669 | ; Apparently PHP doesn't use $TZ. | ||
670 | date.timezone = "${config.time.timeZone}" | ||
671 | ''; | ||
672 | |||
673 | systemd.services.httpdTools = | ||
674 | { description = "Apache HTTPD"; | ||
675 | |||
676 | wantedBy = [ "multi-user.target" ]; | ||
677 | wants = [ "keys.target" ]; | ||
678 | after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ]; | ||
679 | |||
680 | path = | ||
681 | [ httpd pkgs.coreutils pkgs.gnugrep ] | ||
682 | ++ # Needed for PHP's mail() function. !!! Probably the | ||
683 | # ssmtp module should export the path to sendmail in | ||
684 | # some way. | ||
685 | optional config.networking.defaultMailServer.directDelivery pkgs.ssmtp | ||
686 | ++ concatMap (svc: svc.extraServerPath) allSubservices; | ||
687 | |||
688 | environment = | ||
689 | optionalAttrs enablePHP { PHPRC = phpIni; } | ||
690 | // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; } | ||
691 | // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices)); | ||
692 | |||
693 | preStart = | ||
694 | '' | ||
695 | mkdir -m 0750 -p ${mainCfg.stateDir} | ||
696 | [ $(id -u) != 0 ] || chown root.${mainCfg.group} ${mainCfg.stateDir} | ||
697 | ${optionalString version24 '' | ||
698 | mkdir -m 0750 -p "${mainCfg.stateDir}/runtime" | ||
699 | [ $(id -u) != 0 ] || chown root.${mainCfg.group} "${mainCfg.stateDir}/runtime" | ||
700 | ''} | ||
701 | mkdir -m 0700 -p ${mainCfg.logDir} | ||
702 | |||
703 | # Get rid of old semaphores. These tend to accumulate across | ||
704 | # server restarts, eventually preventing it from restarting | ||
705 | # successfully. | ||
706 | for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${mainCfg.user} ' | cut -f2 -d ' '); do | ||
707 | ${pkgs.utillinux}/bin/ipcrm -s $i | ||
708 | done | ||
709 | |||
710 | # Run the startup hooks for the subservices. | ||
711 | for i in ${toString (map (svn: svn.startupScript) allSubservices)}; do | ||
712 | echo Running Apache startup hook $i... | ||
713 | $i | ||
714 | done | ||
715 | ''; | ||
716 | |||
717 | serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf}"; | ||
718 | serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop"; | ||
719 | serviceConfig.ExecReload = "${httpd}/bin/httpd -f ${httpdConf} -k graceful"; | ||
720 | serviceConfig.Type = "forking"; | ||
721 | serviceConfig.PIDFile = "${mainCfg.stateDir}/httpd.pid"; | ||
722 | serviceConfig.Restart = "always"; | ||
723 | serviceConfig.RestartSec = "5s"; | ||
724 | }; | ||
725 | |||
726 | }; | ||
727 | } | ||
diff --git a/virtual/modules/websites/apache/per-server-options.nix b/virtual/modules/websites/apache/per-server-options.nix deleted file mode 100644 index 4bbd041..0000000 --- a/virtual/modules/websites/apache/per-server-options.nix +++ /dev/null | |||
@@ -1,188 +0,0 @@ | |||
1 | # This file defines the options that can be used both for the Apache | ||
2 | # main server configuration, and for the virtual hosts. (The latter | ||
3 | # has additional options that affect the web server as a whole, like | ||
4 | # the user/group to run under.) | ||
5 | |||
6 | { forMainServer, lib }: | ||
7 | |||
8 | with lib; | ||
9 | |||
10 | { | ||
11 | |||
12 | hostName = mkOption { | ||
13 | type = types.str; | ||
14 | default = "localhost"; | ||
15 | description = "Canonical hostname for the server."; | ||
16 | }; | ||
17 | |||
18 | serverAliases = mkOption { | ||
19 | type = types.listOf types.str; | ||
20 | default = []; | ||
21 | example = ["www.example.org" "www.example.org:8080" "example.org"]; | ||
22 | description = '' | ||
23 | Additional names of virtual hosts served by this virtual host configuration. | ||
24 | ''; | ||
25 | }; | ||
26 | |||
27 | port = mkOption { | ||
28 | type = types.int; | ||
29 | default = 0; | ||
30 | description = '' | ||
31 | Port for the server. Option will be removed, use <option>listen</option> instead. | ||
32 | ''; | ||
33 | }; | ||
34 | |||
35 | listen = mkOption { | ||
36 | type = types.listOf (types.submodule ( | ||
37 | { | ||
38 | options = { | ||
39 | port = mkOption { | ||
40 | type = types.int; | ||
41 | description = "port to listen on"; | ||
42 | }; | ||
43 | ip = mkOption { | ||
44 | type = types.string; | ||
45 | default = "*"; | ||
46 | description = "Ip to listen on. 0.0.0.0 for ipv4 only, * for all."; | ||
47 | }; | ||
48 | }; | ||
49 | } )); | ||
50 | description = '' | ||
51 | List of { /* ip: "*"; */ port = 80;} to listen on | ||
52 | ''; | ||
53 | |||
54 | default = []; | ||
55 | }; | ||
56 | |||
57 | enableSSL = mkOption { | ||
58 | type = types.bool; | ||
59 | default = false; | ||
60 | description = "Whether to enable SSL (https) support."; | ||
61 | }; | ||
62 | |||
63 | # Note: sslServerCert and sslServerKey can be left empty, but this | ||
64 | # only makes sense for virtual hosts (they will inherit from the | ||
65 | # main server). | ||
66 | |||
67 | sslServerCert = mkOption { | ||
68 | type = types.nullOr types.path; | ||
69 | default = null; | ||
70 | example = "/var/host.cert"; | ||
71 | description = "Path to server SSL certificate."; | ||
72 | }; | ||
73 | |||
74 | sslServerKey = mkOption { | ||
75 | type = types.path; | ||
76 | example = "/var/host.key"; | ||
77 | description = "Path to server SSL certificate key."; | ||
78 | }; | ||
79 | |||
80 | sslServerChain = mkOption { | ||
81 | type = types.nullOr types.path; | ||
82 | default = null; | ||
83 | example = "/var/ca.pem"; | ||
84 | description = "Path to server SSL chain file."; | ||
85 | }; | ||
86 | |||
87 | adminAddr = mkOption ({ | ||
88 | type = types.nullOr types.str; | ||
89 | example = "admin@example.org"; | ||
90 | description = "E-mail address of the server administrator."; | ||
91 | } // (if forMainServer then {} else {default = null;})); | ||
92 | |||
93 | documentRoot = mkOption { | ||
94 | type = types.nullOr types.path; | ||
95 | default = null; | ||
96 | example = "/data/webserver/docs"; | ||
97 | description = '' | ||
98 | The path of Apache's document root directory. If left undefined, | ||
99 | an empty directory in the Nix store will be used as root. | ||
100 | ''; | ||
101 | }; | ||
102 | |||
103 | servedDirs = mkOption { | ||
104 | type = types.listOf types.attrs; | ||
105 | default = []; | ||
106 | example = [ | ||
107 | { urlPath = "/nix"; | ||
108 | dir = "/home/eelco/Dev/nix-homepage"; | ||
109 | } | ||
110 | ]; | ||
111 | description = '' | ||
112 | This option provides a simple way to serve static directories. | ||
113 | ''; | ||
114 | }; | ||
115 | |||
116 | servedFiles = mkOption { | ||
117 | type = types.listOf types.attrs; | ||
118 | default = []; | ||
119 | example = [ | ||
120 | { urlPath = "/foo/bar.png"; | ||
121 | file = "/home/eelco/some-file.png"; | ||
122 | } | ||
123 | ]; | ||
124 | description = '' | ||
125 | This option provides a simple way to serve individual, static files. | ||
126 | ''; | ||
127 | }; | ||
128 | |||
129 | extraConfig = mkOption { | ||
130 | type = types.lines; | ||
131 | default = ""; | ||
132 | example = '' | ||
133 | <Directory /home> | ||
134 | Options FollowSymlinks | ||
135 | AllowOverride All | ||
136 | </Directory> | ||
137 | ''; | ||
138 | description = '' | ||
139 | These lines go to httpd.conf verbatim. They will go after | ||
140 | directories and directory aliases defined by default. | ||
141 | ''; | ||
142 | }; | ||
143 | |||
144 | extraSubservices = mkOption { | ||
145 | type = types.listOf types.unspecified; | ||
146 | default = []; | ||
147 | description = "Extra subservices to enable in the webserver."; | ||
148 | }; | ||
149 | |||
150 | enableUserDir = mkOption { | ||
151 | type = types.bool; | ||
152 | default = false; | ||
153 | description = '' | ||
154 | Whether to enable serving <filename>~/public_html</filename> as | ||
155 | <literal>/~<replaceable>username</replaceable></literal>. | ||
156 | ''; | ||
157 | }; | ||
158 | |||
159 | globalRedirect = mkOption { | ||
160 | type = types.nullOr types.str; | ||
161 | default = null; | ||
162 | example = http://newserver.example.org/; | ||
163 | description = '' | ||
164 | If set, all requests for this host are redirected permanently to | ||
165 | the given URL. | ||
166 | ''; | ||
167 | }; | ||
168 | |||
169 | logFormat = mkOption { | ||
170 | type = types.str; | ||
171 | default = "common"; | ||
172 | example = "combined"; | ||
173 | description = '' | ||
174 | Log format for Apache's log files. Possible values are: combined, common, referer, agent. | ||
175 | ''; | ||
176 | }; | ||
177 | |||
178 | robotsEntries = mkOption { | ||
179 | type = types.lines; | ||
180 | default = ""; | ||
181 | example = "Disallow: /foo/"; | ||
182 | description = '' | ||
183 | Specification of pages to be ignored by web crawlers. See <link | ||
184 | xlink:href='http://www.robotstxt.org/'/> for details. | ||
185 | ''; | ||
186 | }; | ||
187 | |||
188 | } | ||