2014-04-14 15:26:48 +01:00
|
|
|
{ config, lib, pkgs, ... }:
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2014-04-14 15:26:48 +01:00
|
|
|
with lib;
|
2009-03-06 12:26:41 +00:00
|
|
|
|
2009-07-15 12:19:11 +01:00
|
|
|
let
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2008-04-24 12:56:38 +01:00
|
|
|
mainCfg = config.services.httpd;
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2019-11-04 12:32:28 +00:00
|
|
|
runtimeDir = "/run/httpd";
|
|
|
|
|
2015-10-20 22:49:32 +01:00
|
|
|
httpd = mainCfg.package.out;
|
2012-07-23 20:48:21 +01:00
|
|
|
|
|
|
|
httpdConf = mainCfg.configFile;
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2016-06-22 13:24:25 +01:00
|
|
|
php = mainCfg.phpPackage.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ };
|
|
|
|
|
2019-09-24 10:24:13 +01:00
|
|
|
phpMajorVersion = lib.versions.major (lib.getVersion php);
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2017-06-15 12:07:14 +01:00
|
|
|
mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; };
|
2016-12-15 11:36:07 +00:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
vhosts = attrValues mainCfg.virtualHosts;
|
2016-11-12 14:35:32 +00:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
mkListenInfo = hostOpts:
|
|
|
|
if hostOpts.listen != [] then hostOpts.listen
|
|
|
|
else (
|
|
|
|
optional (hostOpts.onlySSL || hostOpts.addSSL || hostOpts.forceSSL) { ip = "*"; port = 443; ssl = true; } ++
|
|
|
|
optional (!hostOpts.onlySSL) { ip = "*"; port = 80; ssl = false; }
|
|
|
|
);
|
2016-11-12 14:35:32 +00:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
listenInfo = unique (concatMap mkListenInfo vhosts);
|
2008-09-14 02:30:45 +01:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
enableSSL = any (listen: listen.ssl) listenInfo;
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
enableUserDir = any (vhost: vhost.enableUserDir) vhosts;
|
2019-11-09 00:53:56 +00:00
|
|
|
|
2019-11-04 16:21:20 +00:00
|
|
|
# NOTE: generally speaking order of modules is very important
|
|
|
|
modules =
|
|
|
|
[ # required apache modules our httpd service cannot run without
|
|
|
|
"authn_core" "authz_core"
|
|
|
|
"log_config"
|
|
|
|
"mime" "autoindex" "negotiation" "dir"
|
|
|
|
"alias" "rewrite"
|
|
|
|
"unixd" "slotmem_shm" "socache_shmcb"
|
2012-10-17 14:21:32 +01:00
|
|
|
"mpm_${mainCfg.multiProcessingModule}"
|
|
|
|
]
|
2012-07-06 19:23:55 +01:00
|
|
|
++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
|
2010-07-14 13:58:38 +01:00
|
|
|
++ optional enableSSL "ssl"
|
2019-11-09 00:53:56 +00:00
|
|
|
++ optional enableUserDir "userdir"
|
2019-11-04 16:21:20 +00:00
|
|
|
++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
|
|
|
|
++ optional mainCfg.enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; }
|
|
|
|
++ optional mainCfg.enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; }
|
|
|
|
++ mainCfg.extraModules;
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2019-04-20 12:32:55 +01:00
|
|
|
allDenied = "Require all denied";
|
|
|
|
allGranted = "Require all granted";
|
2012-10-17 15:57:18 +01:00
|
|
|
|
|
|
|
|
2014-07-10 13:32:08 +01:00
|
|
|
loggingConf = (if mainCfg.logFormat != "none" then ''
|
2019-01-31 02:04:58 +00:00
|
|
|
ErrorLog ${mainCfg.logDir}/error.log
|
2007-12-12 13:58:15 +00:00
|
|
|
|
|
|
|
LogLevel notice
|
|
|
|
|
|
|
|
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
|
|
|
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
|
|
|
LogFormat "%{Referer}i -> %U" referer
|
|
|
|
LogFormat "%{User-agent}i" agent
|
|
|
|
|
2019-01-31 02:04:58 +00:00
|
|
|
CustomLog ${mainCfg.logDir}/access.log ${mainCfg.logFormat}
|
2014-07-10 13:32:08 +01:00
|
|
|
'' else ''
|
|
|
|
ErrorLog /dev/null
|
|
|
|
'');
|
2007-12-12 13:58:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
browserHacks = ''
|
2019-11-04 16:21:20 +00:00
|
|
|
<IfModule mod_setenvif.c>
|
|
|
|
BrowserMatch "Mozilla/2" nokeepalive
|
|
|
|
BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
|
|
|
|
BrowserMatch "RealPlayer 4\.0" force-response-1.0
|
|
|
|
BrowserMatch "Java/1\.0" force-response-1.0
|
|
|
|
BrowserMatch "JDK/1\.0" force-response-1.0
|
|
|
|
BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
|
|
|
|
BrowserMatch "^WebDrive" redirect-carefully
|
|
|
|
BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully
|
|
|
|
BrowserMatch "^gnome-vfs" redirect-carefully
|
|
|
|
</IfModule>
|
2007-12-12 13:58:15 +00:00
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
|
|
sslConf = ''
|
2019-11-04 12:32:28 +00:00
|
|
|
SSLSessionCache shmcb:${runtimeDir}/ssl_scache(512000)
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2019-04-20 12:32:55 +01:00
|
|
|
Mutex posixsem
|
2007-12-12 13:58:15 +00:00
|
|
|
|
|
|
|
SSLRandomSeed startup builtin
|
|
|
|
SSLRandomSeed connect builtin
|
2015-03-09 13:09:43 +00:00
|
|
|
|
2019-01-09 16:30:19 +00:00
|
|
|
SSLProtocol ${mainCfg.sslProtocols}
|
|
|
|
SSLCipherSuite ${mainCfg.sslCiphers}
|
2015-10-04 22:13:50 +01:00
|
|
|
SSLHonorCipherOrder on
|
2007-12-12 13:58:15 +00:00
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
|
|
mimeConf = ''
|
|
|
|
TypesConfig ${httpd}/conf/mime.types
|
|
|
|
|
|
|
|
AddType application/x-x509-ca-cert .crt
|
|
|
|
AddType application/x-pkcs7-crl .crl
|
2008-02-05 16:25:07 +00:00
|
|
|
AddType application/x-httpd-php .php .phtml
|
2007-12-12 13:58:15 +00:00
|
|
|
|
|
|
|
<IfModule mod_mime_magic.c>
|
|
|
|
MIMEMagicFile ${httpd}/conf/magic
|
|
|
|
</IfModule>
|
|
|
|
'';
|
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
mkVHostConf = hostOpts:
|
|
|
|
let
|
|
|
|
adminAddr = if hostOpts.adminAddr != null then hostOpts.adminAddr else mainCfg.adminAddr;
|
|
|
|
listen = filter (listen: !listen.ssl) (mkListenInfo hostOpts);
|
|
|
|
listenSSL = filter (listen: listen.ssl) (mkListenInfo hostOpts);
|
|
|
|
|
|
|
|
useACME = hostOpts.enableACME || hostOpts.useACMEHost != null;
|
|
|
|
sslCertDir =
|
|
|
|
if hostOpts.enableACME then config.security.acme.certs.${hostOpts.hostName}.directory
|
|
|
|
else if hostOpts.useACMEHost != null then config.security.acme.certs.${hostOpts.useACMEHost}.directory
|
|
|
|
else abort "This case should never happen.";
|
|
|
|
|
|
|
|
sslServerCert = if useACME then "${sslCertDir}/full.pem" else hostOpts.sslServerCert;
|
|
|
|
sslServerKey = if useACME then "${sslCertDir}/key.pem" else hostOpts.sslServerKey;
|
|
|
|
sslServerChain = if useACME then "${sslCertDir}/fullchain.pem" else hostOpts.sslServerChain;
|
|
|
|
|
|
|
|
acmeChallenge = optionalString useACME ''
|
|
|
|
Alias /.well-known/acme-challenge/ "${hostOpts.acmeRoot}/.well-known/acme-challenge/"
|
|
|
|
<Directory "${hostOpts.acmeRoot}">
|
|
|
|
AllowOverride None
|
|
|
|
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
|
|
|
|
Require method GET POST OPTIONS
|
|
|
|
Require all granted
|
|
|
|
</Directory>
|
|
|
|
'';
|
|
|
|
in
|
|
|
|
optionalString (listen != []) ''
|
|
|
|
<VirtualHost ${concatMapStringsSep " " (listen: "${listen.ip}:${toString listen.port}") listen}>
|
|
|
|
ServerName ${hostOpts.hostName}
|
|
|
|
${concatMapStrings (alias: "ServerAlias ${alias}\n") hostOpts.serverAliases}
|
|
|
|
ServerAdmin ${adminAddr}
|
|
|
|
<IfModule mod_ssl.c>
|
|
|
|
SSLEngine off
|
|
|
|
</IfModule>
|
|
|
|
${acmeChallenge}
|
|
|
|
${if hostOpts.forceSSL then ''
|
|
|
|
<IfModule mod_rewrite.c>
|
|
|
|
RewriteEngine on
|
|
|
|
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge [NC]
|
|
|
|
RewriteCond %{HTTPS} off
|
|
|
|
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
|
|
|
</IfModule>
|
|
|
|
'' else mkVHostCommonConf hostOpts}
|
|
|
|
</VirtualHost>
|
|
|
|
'' +
|
|
|
|
optionalString (listenSSL != []) ''
|
|
|
|
<VirtualHost ${concatMapStringsSep " " (listen: "${listen.ip}:${toString listen.port}") listenSSL}>
|
|
|
|
ServerName ${hostOpts.hostName}
|
|
|
|
${concatMapStrings (alias: "ServerAlias ${alias}\n") hostOpts.serverAliases}
|
|
|
|
ServerAdmin ${adminAddr}
|
|
|
|
SSLEngine on
|
|
|
|
SSLCertificateFile ${sslServerCert}
|
|
|
|
SSLCertificateKeyFile ${sslServerKey}
|
|
|
|
${optionalString (sslServerChain != null) "SSLCertificateChainFile ${sslServerChain}"}
|
|
|
|
${acmeChallenge}
|
|
|
|
${mkVHostCommonConf hostOpts}
|
|
|
|
</VirtualHost>
|
|
|
|
''
|
|
|
|
;
|
|
|
|
|
|
|
|
mkVHostCommonConf = hostOpts:
|
|
|
|
let
|
|
|
|
documentRoot = if hostOpts.documentRoot != null
|
|
|
|
then hostOpts.documentRoot
|
|
|
|
else pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out"
|
|
|
|
;
|
|
|
|
in
|
|
|
|
''
|
|
|
|
${optionalString mainCfg.logPerVirtualHost ''
|
|
|
|
ErrorLog ${mainCfg.logDir}/error-${hostOpts.hostName}.log
|
|
|
|
CustomLog ${mainCfg.logDir}/access-${hostOpts.hostName}.log ${hostOpts.logFormat}
|
|
|
|
''}
|
|
|
|
|
|
|
|
${optionalString (hostOpts.robotsEntries != "") ''
|
|
|
|
Alias /robots.txt ${pkgs.writeText "robots.txt" hostOpts.robotsEntries}
|
|
|
|
''}
|
|
|
|
|
|
|
|
DocumentRoot "${documentRoot}"
|
|
|
|
|
|
|
|
<Directory "${documentRoot}">
|
|
|
|
Options Indexes FollowSymLinks
|
|
|
|
AllowOverride None
|
|
|
|
${allGranted}
|
|
|
|
</Directory>
|
|
|
|
|
|
|
|
${optionalString hostOpts.enableUserDir ''
|
|
|
|
UserDir public_html
|
|
|
|
UserDir disabled root
|
|
|
|
<Directory "/home/*/public_html">
|
|
|
|
AllowOverride FileInfo AuthConfig Limit Indexes
|
|
|
|
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
|
|
|
|
<Limit GET POST OPTIONS>
|
|
|
|
Require all granted
|
|
|
|
</Limit>
|
|
|
|
<LimitExcept GET POST OPTIONS>
|
|
|
|
Require all denied
|
|
|
|
</LimitExcept>
|
|
|
|
</Directory>
|
|
|
|
''}
|
|
|
|
|
|
|
|
${optionalString (hostOpts.globalRedirect != null && hostOpts.globalRedirect != "") ''
|
|
|
|
RedirectPermanent / ${hostOpts.globalRedirect}
|
|
|
|
''}
|
|
|
|
|
|
|
|
${
|
|
|
|
let makeFileConf = elem: ''
|
|
|
|
Alias ${elem.urlPath} ${elem.file}
|
|
|
|
'';
|
|
|
|
in concatMapStrings makeFileConf hostOpts.servedFiles
|
|
|
|
}
|
|
|
|
${
|
|
|
|
let makeDirConf = elem: ''
|
|
|
|
Alias ${elem.urlPath} ${elem.dir}/
|
|
|
|
<Directory ${elem.dir}>
|
|
|
|
Options +Indexes
|
|
|
|
${allGranted}
|
|
|
|
AllowOverride All
|
|
|
|
</Directory>
|
|
|
|
'';
|
|
|
|
in concatMapStrings makeDirConf hostOpts.servedDirs
|
|
|
|
}
|
|
|
|
|
|
|
|
${hostOpts.extraConfig}
|
|
|
|
''
|
|
|
|
;
|
2008-02-05 16:25:07 +00:00
|
|
|
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2012-07-23 20:48:21 +01:00
|
|
|
confFile = pkgs.writeText "httpd.conf" ''
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2007-12-12 13:58:15 +00:00
|
|
|
ServerRoot ${httpd}
|
2019-11-04 21:24:55 +00:00
|
|
|
ServerName ${config.networking.hostName}
|
2019-11-04 12:32:28 +00:00
|
|
|
DefaultRuntimeDir ${runtimeDir}/runtime
|
2012-10-17 16:38:43 +01:00
|
|
|
|
2019-11-04 12:32:28 +00:00
|
|
|
PidFile ${runtimeDir}/httpd.pid
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2012-07-06 19:23:55 +01:00
|
|
|
${optionalString (mainCfg.multiProcessingModule != "prefork") ''
|
|
|
|
# mod_cgid requires this.
|
2019-11-04 12:32:28 +00:00
|
|
|
ScriptSock ${runtimeDir}/cgisock
|
2012-07-06 19:23:55 +01:00
|
|
|
''}
|
|
|
|
|
2007-12-12 13:58:15 +00:00
|
|
|
<IfModule prefork.c>
|
2010-04-21 21:55:57 +01:00
|
|
|
MaxClients ${toString mainCfg.maxClients}
|
|
|
|
MaxRequestsPerChild ${toString mainCfg.maxRequestsPerChild}
|
2007-12-12 13:58:15 +00:00
|
|
|
</IfModule>
|
|
|
|
|
2008-04-19 11:21:42 +01:00
|
|
|
${let
|
2019-11-04 21:24:55 +00:00
|
|
|
toStr = listen: "Listen ${listen.ip}:${toString listen.port} ${if listen.ssl then "https" else "http"}";
|
|
|
|
uniqueListen = uniqList {inputList = map toStr listenInfo;};
|
|
|
|
in concatStringsSep "\n" uniqueListen
|
2008-04-19 11:21:42 +01:00
|
|
|
}
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2008-04-24 12:56:38 +01:00
|
|
|
User ${mainCfg.user}
|
|
|
|
Group ${mainCfg.group}
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2008-02-05 16:25:07 +00:00
|
|
|
${let
|
2019-11-04 16:21:20 +00:00
|
|
|
mkModule = module:
|
|
|
|
if isString module then { name = module; path = "${httpd}/modules/mod_${module}.so"; }
|
|
|
|
else if isAttrs module then { inherit (module) name path; }
|
|
|
|
else throw "Expecting either a string or attribute set including a name and path.";
|
|
|
|
in
|
|
|
|
concatMapStringsSep "\n" (module: "LoadModule ${module.name}_module ${module.path}") (unique (map mkModule modules))
|
2007-12-12 13:58:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AddHandler type-map var
|
|
|
|
|
|
|
|
<Files ~ "^\.ht">
|
2012-10-17 15:57:18 +01:00
|
|
|
${allDenied}
|
2007-12-12 13:58:15 +00:00
|
|
|
</Files>
|
|
|
|
|
|
|
|
${mimeConf}
|
|
|
|
${loggingConf}
|
|
|
|
${browserHacks}
|
|
|
|
|
2007-12-12 15:30:17 +00:00
|
|
|
Include ${httpd}/conf/extra/httpd-default.conf
|
2007-12-12 13:58:15 +00:00
|
|
|
Include ${httpd}/conf/extra/httpd-autoindex.conf
|
|
|
|
Include ${httpd}/conf/extra/httpd-multilang-errordoc.conf
|
|
|
|
Include ${httpd}/conf/extra/httpd-languages.conf
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2019-02-07 19:13:45 +00:00
|
|
|
TraceEnable off
|
|
|
|
|
2008-04-24 12:56:38 +01:00
|
|
|
${if enableSSL then sslConf else ""}
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2008-02-05 16:25:07 +00:00
|
|
|
# Fascist default - deny access to everything.
|
2007-12-12 13:58:15 +00:00
|
|
|
<Directory />
|
|
|
|
Options FollowSymLinks
|
|
|
|
AllowOverride None
|
2012-10-17 15:57:18 +01:00
|
|
|
${allDenied}
|
2008-02-14 07:42:52 +00:00
|
|
|
</Directory>
|
|
|
|
|
|
|
|
# But do allow access to files in the store so that we don't have
|
|
|
|
# to generate <Directory> clauses for every generated file that we
|
|
|
|
# want to serve.
|
2011-10-30 15:19:58 +00:00
|
|
|
<Directory /nix/store>
|
2012-10-17 15:57:18 +01:00
|
|
|
${allGranted}
|
2007-12-12 13:58:15 +00:00
|
|
|
</Directory>
|
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
${mainCfg.extraConfig}
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
${concatMapStringsSep "\n" mkVHostConf vhosts}
|
2007-12-12 13:58:15 +00:00
|
|
|
'';
|
|
|
|
|
2010-02-15 19:02:42 +00:00
|
|
|
# Generate the PHP configuration file. Should probably be factored
|
|
|
|
# out into a separate module.
|
|
|
|
phpIni = pkgs.runCommand "php.ini"
|
2019-09-18 02:14:50 +01:00
|
|
|
{ options = mainCfg.phpOptions;
|
2018-11-08 10:59:03 +00:00
|
|
|
preferLocalBuild = true;
|
2010-02-15 19:02:42 +00:00
|
|
|
}
|
|
|
|
''
|
2016-04-29 07:26:20 +01:00
|
|
|
cat ${php}/etc/php.ini > $out
|
2010-02-15 19:02:42 +00:00
|
|
|
echo "$options" >> $out
|
|
|
|
'';
|
|
|
|
|
2007-12-12 13:58:15 +00:00
|
|
|
in
|
|
|
|
|
|
|
|
|
2009-07-15 12:19:11 +01:00
|
|
|
{
|
|
|
|
|
2019-09-18 02:14:50 +01:00
|
|
|
imports = [
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "extraSubservices" ] "Most existing subservices have been ported to the NixOS module system. Please update your configuration accordingly.")
|
2019-11-04 12:32:28 +00:00
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "stateDir" ] "The httpd module now uses /run/httpd as a runtime directory.")
|
2019-11-04 21:24:55 +00:00
|
|
|
|
|
|
|
# virtualHosts options
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "documentRoot" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "enableSSL" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "enableUserDir" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "globalRedirect" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "hostName" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "listen" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "robotsEntries" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "servedDirs" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "servedFiles" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "serverAliases" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "sslServerCert" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "sslServerChain" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
|
|
|
(mkRemovedOptionModule [ "services" "httpd" "sslServerKey" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
|
2019-09-18 02:14:50 +01:00
|
|
|
];
|
|
|
|
|
2009-07-15 12:19:11 +01:00
|
|
|
###### interface
|
|
|
|
|
|
|
|
options = {
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2009-07-15 12:19:11 +01:00
|
|
|
services.httpd = {
|
2011-09-14 19:20:50 +01:00
|
|
|
|
2009-07-15 12:19:11 +01:00
|
|
|
enable = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.bool;
|
2009-07-15 12:19:11 +01:00
|
|
|
default = false;
|
2013-10-29 13:03:39 +00:00
|
|
|
description = "Whether to enable the Apache HTTP Server.";
|
2009-07-15 12:19:11 +01:00
|
|
|
};
|
|
|
|
|
2012-07-24 00:01:48 +01:00
|
|
|
package = mkOption {
|
2014-02-27 12:22:04 +00:00
|
|
|
type = types.package;
|
2014-11-06 13:27:02 +00:00
|
|
|
default = pkgs.apacheHttpd;
|
2016-01-17 18:34:55 +00:00
|
|
|
defaultText = "pkgs.apacheHttpd";
|
2013-10-29 13:03:39 +00:00
|
|
|
description = ''
|
2012-07-23 20:48:21 +01:00
|
|
|
Overridable attribute of the Apache HTTP Server package to use.
|
2013-10-29 13:03:39 +00:00
|
|
|
'';
|
2012-07-23 20:48:21 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
configFile = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.path;
|
2012-07-23 20:48:21 +01:00
|
|
|
default = confFile;
|
2016-01-17 18:34:55 +00:00
|
|
|
defaultText = "confFile";
|
|
|
|
example = literalExample ''pkgs.writeText "httpd.conf" "# my custom config file ..."'';
|
2013-10-29 13:03:39 +00:00
|
|
|
description = ''
|
|
|
|
Override the configuration file used by Apache. By default,
|
|
|
|
NixOS generates one automatically.
|
|
|
|
'';
|
2012-07-23 20:48:21 +01:00
|
|
|
};
|
|
|
|
|
2009-11-06 16:23:25 +00:00
|
|
|
extraConfig = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.lines;
|
2009-11-06 16:23:25 +00:00
|
|
|
default = "";
|
2013-10-29 13:03:39 +00:00
|
|
|
description = ''
|
2019-12-06 18:47:15 +00:00
|
|
|
Configuration lines appended to the generated Apache
|
2013-10-29 13:03:39 +00:00
|
|
|
configuration file. Note that this mechanism may not work
|
|
|
|
when <option>configFile</option> is overridden.
|
|
|
|
'';
|
2009-11-06 16:23:25 +00:00
|
|
|
};
|
|
|
|
|
2009-07-15 12:19:11 +01:00
|
|
|
extraModules = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.listOf types.unspecified;
|
2009-07-15 12:19:11 +01:00
|
|
|
default = [];
|
2019-11-04 16:21:20 +00:00
|
|
|
example = literalExample ''
|
|
|
|
[
|
|
|
|
"proxy_connect"
|
|
|
|
{ name = "jk"; path = "''${pkgs.tomcat_connectors}/modules/mod_jk.so"; }
|
|
|
|
]
|
|
|
|
'';
|
2009-07-15 12:19:11 +01:00
|
|
|
description = ''
|
2013-10-29 13:03:39 +00:00
|
|
|
Additional Apache modules to be used. These can be
|
|
|
|
specified as a string in the case of modules distributed
|
|
|
|
with Apache, or as an attribute set specifying the
|
2009-07-15 12:19:11 +01:00
|
|
|
<varname>name</varname> and <varname>path</varname> of the
|
|
|
|
module.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
adminAddr = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
example = "admin@example.org";
|
|
|
|
description = "E-mail address of the server administrator.";
|
|
|
|
};
|
|
|
|
|
|
|
|
logFormat = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "common";
|
|
|
|
example = "combined";
|
|
|
|
description = ''
|
|
|
|
Log format for log files. Possible values are: combined, common, referer, agent.
|
|
|
|
See <link xlink:href="https://httpd.apache.org/docs/2.4/logs.html"/> for more details.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2009-07-15 12:19:11 +01:00
|
|
|
logPerVirtualHost = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.bool;
|
2019-11-04 21:24:55 +00:00
|
|
|
default = true;
|
2013-10-29 13:03:39 +00:00
|
|
|
description = ''
|
2009-07-15 12:19:11 +01:00
|
|
|
If enabled, each virtual host gets its own
|
2019-02-20 12:43:25 +00:00
|
|
|
<filename>access.log</filename> and
|
|
|
|
<filename>error.log</filename>, namely suffixed by the
|
2009-07-15 12:19:11 +01:00
|
|
|
<option>hostName</option> of the virtual host.
|
2013-10-29 13:03:39 +00:00
|
|
|
'';
|
2009-07-15 12:19:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
user = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.str;
|
2009-07-15 12:19:11 +01:00
|
|
|
default = "wwwrun";
|
2013-10-29 13:03:39 +00:00
|
|
|
description = ''
|
2009-07-15 12:19:11 +01:00
|
|
|
User account under which httpd runs. The account is created
|
|
|
|
automatically if it doesn't exist.
|
2013-10-29 13:03:39 +00:00
|
|
|
'';
|
2009-07-15 12:19:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
group = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.str;
|
2009-07-15 12:19:11 +01:00
|
|
|
default = "wwwrun";
|
2013-10-29 13:03:39 +00:00
|
|
|
description = ''
|
2009-07-15 12:19:11 +01:00
|
|
|
Group under which httpd runs. The account is created
|
|
|
|
automatically if it doesn't exist.
|
2013-10-29 13:03:39 +00:00
|
|
|
'';
|
2009-07-15 12:19:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
logDir = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.path;
|
2009-07-15 12:19:11 +01:00
|
|
|
default = "/var/log/httpd";
|
2013-10-29 13:03:39 +00:00
|
|
|
description = ''
|
2009-07-15 12:19:11 +01:00
|
|
|
Directory for Apache's log files. It is created automatically.
|
2013-10-29 13:03:39 +00:00
|
|
|
'';
|
2009-07-15 12:19:11 +01:00
|
|
|
};
|
|
|
|
|
2009-11-06 16:23:25 +00:00
|
|
|
virtualHosts = mkOption {
|
2019-11-04 21:24:55 +00:00
|
|
|
type = with types; attrsOf (submodule (import ./per-server-options.nix));
|
|
|
|
default = {
|
|
|
|
localhost = {
|
|
|
|
documentRoot = "${httpd}/htdocs";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
example = literalExample ''
|
|
|
|
{
|
|
|
|
"foo.example.com" = {
|
|
|
|
forceSSL = true;
|
|
|
|
documentRoot = "/var/www/foo.example.com"
|
|
|
|
};
|
|
|
|
"bar.example.com" = {
|
|
|
|
addSSL = true;
|
|
|
|
documentRoot = "/var/www/bar.example.com";
|
2013-10-28 20:58:32 +00:00
|
|
|
};
|
2009-11-06 16:23:25 +00:00
|
|
|
}
|
2019-11-04 21:24:55 +00:00
|
|
|
'';
|
2009-11-06 16:23:25 +00:00
|
|
|
description = ''
|
2019-11-04 21:24:55 +00:00
|
|
|
Specification of the virtual hosts served by Apache. Each
|
2009-11-06 16:23:25 +00:00
|
|
|
element should be an attribute set specifying the
|
2019-11-04 21:24:55 +00:00
|
|
|
configuration of the virtual host.
|
2009-11-06 16:23:25 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2016-02-06 21:27:48 +00:00
|
|
|
enableMellon = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = "Whether to enable the mod_auth_mellon module.";
|
|
|
|
};
|
|
|
|
|
2014-05-20 10:50:39 +01:00
|
|
|
enablePHP = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = "Whether to enable the PHP module.";
|
|
|
|
};
|
|
|
|
|
2016-06-22 13:24:25 +01:00
|
|
|
phpPackage = mkOption {
|
|
|
|
type = types.package;
|
|
|
|
default = pkgs.php;
|
|
|
|
defaultText = "pkgs.php";
|
|
|
|
description = ''
|
|
|
|
Overridable attribute of the PHP package to use.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2016-12-15 11:36:07 +00:00
|
|
|
enablePerl = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = "Whether to enable the Perl module (mod_perl).";
|
|
|
|
};
|
|
|
|
|
2010-02-15 19:02:42 +00:00
|
|
|
phpOptions = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.lines;
|
2010-02-15 19:02:42 +00:00
|
|
|
default = "";
|
|
|
|
example =
|
|
|
|
''
|
|
|
|
date.timezone = "CET"
|
|
|
|
'';
|
|
|
|
description =
|
|
|
|
"Options appended to the PHP configuration file <filename>php.ini</filename>.";
|
2010-01-07 09:01:40 +00:00
|
|
|
};
|
|
|
|
|
2012-07-06 19:23:55 +01:00
|
|
|
multiProcessingModule = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.str;
|
2012-07-06 19:23:55 +01:00
|
|
|
default = "prefork";
|
|
|
|
example = "worker";
|
|
|
|
description =
|
|
|
|
''
|
|
|
|
Multi-processing module to be used by Apache. Available
|
|
|
|
modules are <literal>prefork</literal> (the default;
|
|
|
|
handles each request in a separate child process),
|
|
|
|
<literal>worker</literal> (hybrid approach that starts a
|
|
|
|
number of child processes each running a number of
|
|
|
|
threads) and <literal>event</literal> (a recent variant of
|
|
|
|
<literal>worker</literal> that handles persistent
|
|
|
|
connections more efficiently).
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2010-04-21 21:55:57 +01:00
|
|
|
maxClients = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.int;
|
2010-04-21 21:55:57 +01:00
|
|
|
default = 150;
|
|
|
|
example = 8;
|
|
|
|
description = "Maximum number of httpd processes (prefork)";
|
|
|
|
};
|
|
|
|
|
|
|
|
maxRequestsPerChild = mkOption {
|
2013-10-29 13:03:39 +00:00
|
|
|
type = types.int;
|
2010-04-21 21:55:57 +01:00
|
|
|
default = 0;
|
|
|
|
example = 500;
|
|
|
|
description =
|
|
|
|
"Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited";
|
|
|
|
};
|
2019-01-09 16:30:19 +00:00
|
|
|
|
|
|
|
sslCiphers = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "HIGH:!aNULL:!MD5:!EXP";
|
|
|
|
description = "Cipher Suite available for negotiation in SSL proxy handshake.";
|
|
|
|
};
|
|
|
|
|
|
|
|
sslProtocols = mkOption {
|
|
|
|
type = types.str;
|
2019-12-30 16:24:11 +00:00
|
|
|
default = "All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1";
|
2019-02-07 19:05:44 +00:00
|
|
|
example = "All -SSLv2 -SSLv3";
|
2019-01-09 16:30:19 +00:00
|
|
|
description = "Allowed SSL/TLS protocol versions.";
|
|
|
|
};
|
2019-11-04 21:24:55 +00:00
|
|
|
};
|
2009-07-15 12:19:11 +01:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
|
|
|
config = mkIf config.services.httpd.enable {
|
2014-11-06 13:27:02 +00:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
assertions = [
|
|
|
|
{
|
|
|
|
assertion = all (hostOpts: !hostOpts.enableSSL) vhosts;
|
|
|
|
message = ''
|
|
|
|
The option `services.httpd.virtualHosts.<name>.enableSSL` no longer has any effect; please remove it.
|
|
|
|
Select one of `services.httpd.virtualHosts.<name>.addSSL`, `services.httpd.virtualHosts.<name>.forceSSL`,
|
|
|
|
or `services.httpd.virtualHosts.<name>.onlySSL`.
|
|
|
|
'';
|
|
|
|
}
|
|
|
|
{
|
|
|
|
assertion = all (hostOpts: with hostOpts; !(addSSL && onlySSL) && !(forceSSL && onlySSL) && !(addSSL && forceSSL)) vhosts;
|
|
|
|
message = ''
|
|
|
|
Options `services.httpd.virtualHosts.<name>.addSSL`,
|
|
|
|
`services.httpd.virtualHosts.<name>.onlySSL` and `services.httpd.virtualHosts.<name>.forceSSL`
|
|
|
|
are mutually exclusive.
|
|
|
|
'';
|
|
|
|
}
|
|
|
|
{
|
|
|
|
assertion = all (hostOpts: !(hostOpts.enableACME && hostOpts.useACMEHost != null)) vhosts;
|
|
|
|
message = ''
|
|
|
|
Options `services.httpd.virtualHosts.<name>.enableACME` and
|
|
|
|
`services.httpd.virtualHosts.<name>.useACMEHost` are mutually exclusive.
|
|
|
|
'';
|
|
|
|
}
|
|
|
|
];
|
2009-07-15 12:19:11 +01:00
|
|
|
|
2019-09-14 18:51:29 +01:00
|
|
|
users.users = optionalAttrs (mainCfg.user == "wwwrun") {
|
|
|
|
wwwrun = {
|
2014-06-11 10:36:15 +01:00
|
|
|
group = mainCfg.group;
|
2009-03-06 12:26:41 +00:00
|
|
|
description = "Apache httpd user";
|
2012-08-03 16:05:25 +01:00
|
|
|
uid = config.ids.uids.wwwrun;
|
2019-09-14 18:51:29 +01:00
|
|
|
};
|
|
|
|
};
|
2009-07-15 12:19:11 +01:00
|
|
|
|
2019-09-14 18:51:29 +01:00
|
|
|
users.groups = optionalAttrs (mainCfg.group == "wwwrun") {
|
|
|
|
wwwrun.gid = config.ids.gids.wwwrun;
|
|
|
|
};
|
2007-12-12 13:58:15 +00:00
|
|
|
|
2019-11-04 21:24:55 +00:00
|
|
|
security.acme.certs = mapAttrs (name: hostOpts: {
|
|
|
|
user = mainCfg.user;
|
|
|
|
group = mkDefault mainCfg.group;
|
|
|
|
email = if hostOpts.adminAddr != null then hostOpts.adminAddr else mainCfg.adminAddr;
|
|
|
|
webroot = hostOpts.acmeRoot;
|
|
|
|
extraDomains = genAttrs hostOpts.serverAliases (alias: null);
|
|
|
|
postRun = "systemctl reload httpd.service";
|
|
|
|
}) (filterAttrs (name: hostOpts: hostOpts.enableACME) mainCfg.virtualHosts);
|
|
|
|
|
2019-09-18 02:14:50 +01:00
|
|
|
environment.systemPackages = [httpd];
|
2009-03-06 12:26:41 +00:00
|
|
|
|
2010-02-15 19:02:42 +00:00
|
|
|
services.httpd.phpOptions =
|
|
|
|
''
|
|
|
|
; Needed for PHP's mail() function.
|
|
|
|
sendmail_path = sendmail -t -i
|
2019-02-07 19:25:55 +00:00
|
|
|
|
|
|
|
; Don't advertise PHP
|
|
|
|
expose_php = off
|
2019-04-24 04:48:22 +01:00
|
|
|
'' + optionalString (config.time.timeZone != null) ''
|
2010-02-15 19:02:42 +00:00
|
|
|
|
|
|
|
; Apparently PHP doesn't use $TZ.
|
|
|
|
date.timezone = "${config.time.timeZone}"
|
|
|
|
'';
|
|
|
|
|
2019-11-04 16:21:20 +00:00
|
|
|
services.httpd.extraModules = mkBefore [
|
|
|
|
# HTTP authentication mechanisms: basic and digest.
|
|
|
|
"auth_basic" "auth_digest"
|
|
|
|
|
|
|
|
# Authentication: is the user who he claims to be?
|
|
|
|
"authn_file" "authn_dbm" "authn_anon"
|
|
|
|
|
|
|
|
# Authorization: is the user allowed access?
|
|
|
|
"authz_user" "authz_groupfile" "authz_host"
|
|
|
|
|
|
|
|
# Other modules.
|
|
|
|
"ext_filter" "include" "env" "mime_magic"
|
|
|
|
"cern_meta" "expires" "headers" "usertrack" "setenvif"
|
|
|
|
"dav" "status" "asis" "info" "dav_fs"
|
|
|
|
"vhost_alias" "imagemap" "actions" "speling"
|
|
|
|
"proxy" "proxy_http"
|
|
|
|
"cache" "cache_disk"
|
|
|
|
|
|
|
|
# For compatibility with old configurations, the new module mod_access_compat is provided.
|
|
|
|
"access_compat"
|
|
|
|
];
|
|
|
|
|
2013-01-16 11:33:18 +00:00
|
|
|
systemd.services.httpd =
|
2019-11-04 21:24:55 +00:00
|
|
|
let
|
|
|
|
vhostsACME = filter (hostOpts: hostOpts.enableACME) vhosts;
|
|
|
|
in
|
2012-06-16 05:19:43 +01:00
|
|
|
{ description = "Apache HTTPD";
|
2009-10-12 18:09:38 +01:00
|
|
|
|
2012-08-14 23:15:37 +01:00
|
|
|
wantedBy = [ "multi-user.target" ];
|
2019-11-04 21:24:55 +00:00
|
|
|
wants = concatLists (map (hostOpts: [ "acme-${hostOpts.hostName}.service" "acme-selfsigned-${hostOpts.hostName}.service" ]) vhostsACME);
|
|
|
|
after = [ "network.target" "fs.target" ] ++ map (hostOpts: "acme-selfsigned-${hostOpts.hostName}.service") vhostsACME;
|
2009-10-12 18:09:38 +01:00
|
|
|
|
2011-11-25 16:32:54 +00:00
|
|
|
path =
|
|
|
|
[ httpd pkgs.coreutils pkgs.gnugrep ]
|
2019-09-18 02:14:50 +01:00
|
|
|
++ optional mainCfg.enablePHP pkgs.system-sendmail; # Needed for PHP's mail() function.
|
2011-08-09 15:07:44 +01:00
|
|
|
|
2011-11-25 16:32:54 +00:00
|
|
|
environment =
|
2019-09-18 02:14:50 +01:00
|
|
|
optionalAttrs mainCfg.enablePHP { PHPRC = phpIni; }
|
|
|
|
// optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; };
|
2009-10-12 18:09:38 +01:00
|
|
|
|
|
|
|
preStart =
|
|
|
|
''
|
|
|
|
mkdir -m 0700 -p ${mainCfg.logDir}
|
|
|
|
|
|
|
|
# Get rid of old semaphores. These tend to accumulate across
|
|
|
|
# server restarts, eventually preventing it from restarting
|
2013-08-10 22:07:13 +01:00
|
|
|
# successfully.
|
2009-10-12 18:09:38 +01:00
|
|
|
for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${mainCfg.user} ' | cut -f2 -d ' '); do
|
|
|
|
${pkgs.utillinux}/bin/ipcrm -s $i
|
|
|
|
done
|
|
|
|
'';
|
|
|
|
|
2013-07-09 14:08:48 +01:00
|
|
|
serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf}";
|
2012-11-01 22:32:12 +00:00
|
|
|
serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop";
|
2016-04-07 16:52:48 +01:00
|
|
|
serviceConfig.ExecReload = "${httpd}/bin/httpd -f ${httpdConf} -k graceful";
|
2019-11-04 12:32:28 +00:00
|
|
|
serviceConfig.Group = mainCfg.group;
|
2013-07-09 14:08:48 +01:00
|
|
|
serviceConfig.Type = "forking";
|
2019-11-04 12:32:28 +00:00
|
|
|
serviceConfig.PIDFile = "${runtimeDir}/httpd.pid";
|
2012-11-01 22:32:12 +00:00
|
|
|
serviceConfig.Restart = "always";
|
2015-01-19 21:47:44 +00:00
|
|
|
serviceConfig.RestartSec = "5s";
|
2019-11-04 12:32:28 +00:00
|
|
|
serviceConfig.RuntimeDirectory = "httpd httpd/runtime";
|
|
|
|
serviceConfig.RuntimeDirectoryMode = "0750";
|
2009-10-12 18:09:38 +01:00
|
|
|
};
|
|
|
|
|
2009-03-06 12:26:41 +00:00
|
|
|
};
|
2007-12-12 13:58:15 +00:00
|
|
|
}
|