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