diff --git a/nixos/doc/manual/configuration/abstractions.xml b/nixos/doc/manual/configuration/abstractions.xml
index 5bf0635cc1aa..df9ff2615e1a 100644
--- a/nixos/doc/manual/configuration/abstractions.xml
+++ b/nixos/doc/manual/configuration/abstractions.xml
@@ -11,50 +11,46 @@
{
=
- [ { hostName = "example.org";
- documentRoot = "/webroot";
+ { "blog.example.org" = {
+ documentRoot = "/webroot/blog.example.org";
adminAddr = "alice@example.org";
- enableUserDir = true;
- }
- { hostName = "example.org";
- documentRoot = "/webroot";
+ forceSSL = true;
+ enableACME = true;
+ enablePHP = true;
+ };
+ "wiki.example.org" = {
+ documentRoot = "/webroot/wiki.example.org";
adminAddr = "alice@example.org";
- enableUserDir = true;
- enableSSL = true;
- sslServerCert = "/root/ssl-example-org.crt";
- sslServerKey = "/root/ssl-example-org.key";
- }
- ];
+ forceSSL = true;
+ enableACME = true;
+ enablePHP = true;
+ };
+ };
}
It defines two virtual hosts with nearly identical configuration; the only
- difference is that the second one has SSL enabled. To prevent this
+ difference is the document root directories. To prevent this
duplication, we can use a let:
let
- exampleOrgCommon =
- { hostName = "example.org";
- documentRoot = "/webroot";
- adminAddr = "alice@example.org";
- enableUserDir = true;
+ commonConfig =
+ { adminAddr = "alice@example.org";
+ forceSSL = true;
+ enableACME = true;
};
in
{
=
- [ exampleOrgCommon
- (exampleOrgCommon // {
- enableSSL = true;
- sslServerCert = "/root/ssl-example-org.crt";
- sslServerKey = "/root/ssl-example-org.key";
- })
- ];
+ { "blog.example.org" = (commonConfig // { documentRoot = "/webroot/blog.example.org"; });
+ "wiki.example.org" = (commonConfig // { documentRoot = "/webroot/wiki.example.com"; });
+ };
}
- The let exampleOrgCommon = ...
- defines a variable named exampleOrgCommon. The
+ The let commonConfig = ...
+ defines a variable named commonConfig. The
// operator merges two attribute sets, so the
configuration of the second virtual host is the set
- exampleOrgCommon extended with the SSL options.
+ commonConfig extended with the document root option.
@@ -63,13 +59,13 @@ in
{
=
- let exampleOrgCommon = ...; in
- [ exampleOrgCommon
- (exampleOrgCommon // { ... })
- ];
+ let commonConfig = ...; in
+ { "blog.example.org" = (commonConfig // { ... })
+ "wiki.example.org" = (commonConfig // { ... })
+ };
}
- but not { let exampleOrgCommon = ...; in
+ but not { let commonConfig = ...; in
...; } since attributes (as opposed to
attribute values) are not expressions.
@@ -77,80 +73,29 @@ in
Functions provide another method of abstraction. For
instance, suppose that we want to generate lots of different virtual hosts,
- all with identical configuration except for the host name. This can be done
+ all with identical configuration except for the document root. This can be done
as follows:
{
=
let
- makeVirtualHost = name:
- { hostName = name;
- documentRoot = "/webroot";
+ makeVirtualHost = webroot:
+ { documentRoot = webroot;
adminAddr = "alice@example.org";
+ forceSSL = true;
+ enableACME = true;
};
in
- [ (makeVirtualHost "example.org")
- (makeVirtualHost "example.com")
- (makeVirtualHost "example.gov")
- (makeVirtualHost "example.nl")
- ];
+ { "example.org" = (makeVirtualHost "/webroot/example.org");
+ "example.com" = (makeVirtualHost "/webroot/example.com");
+ "example.gov" = (makeVirtualHost "/webroot/example.gov");
+ "example.nl" = (makeVirtualHost "/webroot/example.nl");
+ };
}
Here, makeVirtualHost is a function that takes a single
- argument name and returns the configuration for a virtual
+ argument webroot and returns the configuration for a virtual
host. That function is then called for several names to produce the list of
virtual host configurations.
-
-
- We can further improve on this by using the function map,
- which applies another function to every element in a list:
-
-{
- =
- let
- makeVirtualHost = ...;
- in map makeVirtualHost
- [ "example.org" "example.com" "example.gov" "example.nl" ];
-}
-
- (The function map is called a higher-order
- function because it takes another function as an argument.)
-
-
-
- What if you need more than one argument, for instance, if we want to use a
- different documentRoot for each virtual host? Then we can
- make makeVirtualHost a function that takes a
- set as its argument, like this:
-
-{
- =
- let
- makeVirtualHost = { name, root }:
- { hostName = name;
- documentRoot = root;
- adminAddr = "alice@example.org";
- };
- in map makeVirtualHost
- [ { name = "example.org"; root = "/sites/example.org"; }
- { name = "example.com"; root = "/sites/example.com"; }
- { name = "example.gov"; root = "/sites/example.gov"; }
- { name = "example.nl"; root = "/sites/example.nl"; }
- ];
-}
-
- But in this case (where every root is a subdirectory of
- /sites named after the virtual host), it would have been
- shorter to define makeVirtualHost as
-
-makeVirtualHost = name:
- { hostName = name;
- documentRoot = "/sites/${name}";
- adminAddr = "alice@example.org";
- };
-
- Here, the construct ${...}
- allows the result of an expression to be spliced into a string.
-
diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml
index eadafb94b8f6..7ccb5b3664ea 100644
--- a/nixos/doc/manual/configuration/config-file.xml
+++ b/nixos/doc/manual/configuration/config-file.xml
@@ -27,7 +27,7 @@
{ = true;
= "alice@example.org";
- = "/webroot";
+ services.httpd.virtualHosts.localhost.documentRoot = "/webroot";
}
defines a configuration with three option definitions that together enable
@@ -50,7 +50,11 @@
httpd = {
enable = true;
adminAddr = "alice@example.org";
- documentRoot = "/webroot";
+ virtualHosts = {
+ localhost = {
+ documentRoot = "/webroot";
+ };
+ };
};
};
}
diff --git a/nixos/doc/manual/release-notes/rl-2003.xml b/nixos/doc/manual/release-notes/rl-2003.xml
index d54d2cd87aee..1c1c8908064a 100644
--- a/nixos/doc/manual/release-notes/rl-2003.xml
+++ b/nixos/doc/manual/release-notes/rl-2003.xml
@@ -327,6 +327,28 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
module.
+
+
+ The httpd module no longer provides options to support serving web content without defining a virtual host. As a
+ result of this the services.httpd.logPerVirtualHost
+ option now defaults to true instead of false. Please update your
+ configuration to make use of services.httpd.virtualHosts.
+
+
+ The services.httpd.virtualHosts.<name>
+ option has changed type from a list of submodules to an attribute set of submodules, better matching
+ services.nginx.virtualHosts.<name>.
+
+
+ This change comes with the addition of the following options which mimic the functionality of their nginx counterparts:
+ services.httpd.virtualHosts.<name>.addSSL,
+ services.httpd.virtualHosts.<name>.forceSSL,
+ services.httpd.virtualHosts.<name>.onlySSL,
+ services.httpd.virtualHosts.<name>.enableACME,
+ services.httpd.virtualHosts.<name>.acmeRoot, and
+ services.httpd.virtualHosts.<name>.useACMEHost.
+
+
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index 6a3b97769462..4128bc12030f 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -8,6 +8,7 @@ let
nagiosState = "/var/lib/nagios";
nagiosLogDir = "/var/log/nagios";
+ urlPath = "/nagios";
nagiosObjectDefs = cfg.objectDefs;
@@ -49,12 +50,12 @@ let
''
main_config_file=${cfg.mainConfigFile}
use_authentication=0
- url_html_path=${cfg.urlPath}
+ url_html_path=${urlPath}
'';
extraHttpdConfig =
''
- ScriptAlias ${cfg.urlPath}/cgi-bin ${pkgs.nagios}/sbin
+ ScriptAlias ${urlPath}/cgi-bin ${pkgs.nagios}/sbin
Options ExecCGI
@@ -62,7 +63,7 @@ let
SetEnv NAGIOS_CGI_CONFIG ${cfg.cgiConfigFile}
- Alias ${cfg.urlPath} ${pkgs.nagios}/share
+ Alias ${urlPath} ${pkgs.nagios}/share
Options None
@@ -72,6 +73,10 @@ let
in
{
+ imports = [
+ (mkRemovedOptionModule [ "services" "nagios" "urlPath" ] "The urlPath option has been removed as it is hard coded to /nagios in the nagios package.")
+ ];
+
options = {
services.nagios = {
enable = mkOption {
@@ -128,13 +133,20 @@ in
";
};
- urlPath = mkOption {
- default = "/nagios";
- description = "
- The URL path under which the Nagios web interface appears.
- That is, you can access the Nagios web interface through
- http://server/urlPath.
- ";
+ virtualHost = mkOption {
+ type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ example = literalExample ''
+ { hostName = "example.org";
+ adminAddr = "webmaster@example.org";
+ enableSSL = true;
+ sslServerCert = "/var/lib/acme/example.org/full.pem";
+ sslServerKey = "/var/lib/acme/example.org/key.pem";
+ }
+ '';
+ description = ''
+ Apache configuration can be done by adapting .
+ See for further information.
+ '';
};
};
};
@@ -182,6 +194,8 @@ in
'';
};
- services.httpd.extraConfig = optionalString cfg.enableWebInterface extraHttpdConfig;
+ services.httpd.virtualHosts = optionalAttrs cfg.enableWebInterface {
+ ${cfg.virtualHost.hostName} = mkMerge [ cfg.virtualHost { extraConfig = extraHttpdConfig; } ];
+ };
};
}
diff --git a/nixos/modules/services/web-apps/limesurvey.nix b/nixos/modules/services/web-apps/limesurvey.nix
index bd524524130d..e00a47191c6f 100644
--- a/nixos/modules/services/web-apps/limesurvey.nix
+++ b/nixos/modules/services/web-apps/limesurvey.nix
@@ -3,7 +3,7 @@
let
inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption;
- inherit (lib) mapAttrs optional optionalString types;
+ inherit (lib) literalExample mapAttrs optional optionalString types;
cfg = config.services.limesurvey;
fpm = config.services.phpfpm.pools.limesurvey;
@@ -100,19 +100,15 @@ in
};
virtualHost = mkOption {
- type = types.submodule ({
- options = import ../web-servers/apache-httpd/per-server-options.nix {
- inherit lib;
- forMainServer = false;
- };
- });
- example = {
- hostName = "survey.example.org";
- enableSSL = true;
- adminAddr = "webmaster@example.org";
- sslServerCert = "/var/lib/acme/survey.example.org/full.pem";
- sslServerKey = "/var/lib/acme/survey.example.org/key.pem";
- };
+ type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ example = literalExample ''
+ {
+ hostName = "survey.example.org";
+ adminAddr = "webmaster@example.org";
+ forceSSL = true;
+ enableACME = true;
+ }
+ '';
description = ''
Apache configuration can be done by adapting services.httpd.virtualHosts.<name>.
See for further information.
@@ -184,7 +180,7 @@ in
config = {
tempdir = "${stateDir}/tmp";
uploaddir = "${stateDir}/upload";
- force_ssl = mkIf cfg.virtualHost.enableSSL "on";
+ force_ssl = mkIf (cfg.virtualHost.addSSL || cfg.virtualHost.forceSSL || cfg.virtualHost.onlySSL) "on";
config.defaultlang = "en";
};
};
@@ -215,38 +211,36 @@ in
enable = true;
adminAddr = mkDefault cfg.virtualHost.adminAddr;
extraModules = [ "proxy_fcgi" ];
- virtualHosts = [ (mkMerge [
- cfg.virtualHost {
- documentRoot = mkForce "${pkg}/share/limesurvey";
- extraConfig = ''
- Alias "/tmp" "${stateDir}/tmp"
-
- AllowOverride all
- Require all granted
- Options -Indexes +FollowSymlinks
-
+ virtualHosts.${cfg.virtualHost.hostName} = mkMerge [ cfg.virtualHost {
+ documentRoot = mkForce "${pkg}/share/limesurvey";
+ extraConfig = ''
+ Alias "/tmp" "${stateDir}/tmp"
+
+ AllowOverride all
+ Require all granted
+ Options -Indexes +FollowSymlinks
+
- Alias "/upload" "${stateDir}/upload"
-
- AllowOverride all
- Require all granted
- Options -Indexes
-
+ Alias "/upload" "${stateDir}/upload"
+
+ AllowOverride all
+ Require all granted
+ Options -Indexes
+
-
-
-
- SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
-
-
+
+
+
+ SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
+
+
- AllowOverride all
- Options -Indexes
- DirectoryIndex index.php
-
- '';
- }
- ]) ];
+ AllowOverride all
+ Options -Indexes
+ DirectoryIndex index.php
+
+ '';
+ } ];
};
systemd.tmpfiles.rules = [
diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix
index 43edc04e1a49..8a109b39bb57 100644
--- a/nixos/modules/services/web-apps/mediawiki.nix
+++ b/nixos/modules/services/web-apps/mediawiki.nix
@@ -64,7 +64,7 @@ let
$wgScriptPath = "";
## The protocol and server name to use in fully-qualified URLs
- $wgServer = "${if cfg.virtualHost.enableSSL then "https" else "http"}://${cfg.virtualHost.hostName}";
+ $wgServer = "${if cfg.virtualHost.addSSL || cfg.virtualHost.forceSSL || cfg.virtualHost.onlySSL then "https" else "http"}://${cfg.virtualHost.hostName}";
## The URL path to static resources (images, scripts, etc.)
$wgResourceBasePath = $wgScriptPath;
@@ -290,19 +290,13 @@ in
};
virtualHost = mkOption {
- type = types.submodule ({
- options = import ../web-servers/apache-httpd/per-server-options.nix {
- inherit lib;
- forMainServer = false;
- };
- });
+ type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
example = literalExample ''
{
hostName = "mediawiki.example.org";
- enableSSL = true;
adminAddr = "webmaster@example.org";
- sslServerCert = "/var/lib/acme/mediawiki.example.org/full.pem";
- sslServerKey = "/var/lib/acme/mediawiki.example.org/key.pem";
+ forceSSL = true;
+ enableACME = true;
}
'';
description = ''
@@ -389,31 +383,28 @@ in
services.httpd = {
enable = true;
- adminAddr = mkDefault cfg.virtualHost.adminAddr;
extraModules = [ "proxy_fcgi" ];
- virtualHosts = [ (mkMerge [
- cfg.virtualHost {
- documentRoot = mkForce "${pkg}/share/mediawiki";
- extraConfig = ''
-
-
-
- SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
-
-
+ virtualHosts.${cfg.virtualHost.hostName} = mkMerge [ cfg.virtualHost {
+ documentRoot = mkForce "${pkg}/share/mediawiki";
+ extraConfig = ''
+
+
+
+ SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
+
+
- Require all granted
- DirectoryIndex index.php
- AllowOverride All
-
- '' + optionalString (cfg.uploadsDir != null) ''
- Alias "/images" "${cfg.uploadsDir}"
-
- Require all granted
-
- '';
- }
- ]) ];
+ Require all granted
+ DirectoryIndex index.php
+ AllowOverride All
+
+ '' + optionalString (cfg.uploadsDir != null) ''
+ Alias "/images" "${cfg.uploadsDir}"
+
+ Require all granted
+
+ '';
+ } ];
};
systemd.tmpfiles.rules = [
diff --git a/nixos/modules/services/web-apps/moodle.nix b/nixos/modules/services/web-apps/moodle.nix
index ac59f9e0012a..595d070d940a 100644
--- a/nixos/modules/services/web-apps/moodle.nix
+++ b/nixos/modules/services/web-apps/moodle.nix
@@ -32,7 +32,7 @@ let
'dbcollation' => 'utf8mb4_unicode_ci',
);
- $CFG->wwwroot = '${if cfg.virtualHost.enableSSL then "https" else "http"}://${cfg.virtualHost.hostName}';
+ $CFG->wwwroot = '${if cfg.virtualHost.addSSL || cfg.virtualHost.forceSSL || cfg.virtualHost.onlySSL then "https" else "http"}://${cfg.virtualHost.hostName}';
$CFG->dataroot = '${stateDir}';
$CFG->admin = 'admin';
@@ -140,19 +140,15 @@ in
};
virtualHost = mkOption {
- type = types.submodule ({
- options = import ../web-servers/apache-httpd/per-server-options.nix {
- inherit lib;
- forMainServer = false;
- };
- });
- example = {
- hostName = "moodle.example.org";
- enableSSL = true;
- adminAddr = "webmaster@example.org";
- sslServerCert = "/var/lib/acme/moodle.example.org/full.pem";
- sslServerKey = "/var/lib/acme/moodle.example.org/key.pem";
- };
+ type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ example = literalExample ''
+ {
+ hostName = "moodle.example.org";
+ adminAddr = "webmaster@example.org";
+ forceSSL = true;
+ enableACME = true;
+ }
+ '';
description = ''
Apache configuration can be done by adapting .
See for further information.
@@ -241,22 +237,20 @@ in
enable = true;
adminAddr = mkDefault cfg.virtualHost.adminAddr;
extraModules = [ "proxy_fcgi" ];
- virtualHosts = [ (mkMerge [
- cfg.virtualHost {
- documentRoot = mkForce "${cfg.package}/share/moodle";
- extraConfig = ''
-
-
-
- SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
-
-
- Options -Indexes
- DirectoryIndex index.php
-
- '';
- }
- ]) ];
+ virtualHosts.${cfg.virtualHost.hostName} = mkMerge [ cfg.virtualHost {
+ documentRoot = mkForce "${cfg.package}/share/moodle";
+ extraConfig = ''
+
+
+
+ SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
+
+
+ Options -Indexes
+ DirectoryIndex index.php
+
+ '';
+ } ];
};
systemd.tmpfiles.rules = [
diff --git a/nixos/modules/services/web-apps/wordpress.nix b/nixos/modules/services/web-apps/wordpress.nix
index 13d21a0b4aed..ad4f39fbf52c 100644
--- a/nixos/modules/services/web-apps/wordpress.nix
+++ b/nixos/modules/services/web-apps/wordpress.nix
@@ -3,7 +3,7 @@
let
inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
inherit (lib) any attrValues concatMapStringsSep flatten literalExample;
- inherit (lib) mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString;
+ inherit (lib) mapAttrs mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString;
eachSite = config.services.wordpress;
user = "wordpress";
@@ -209,18 +209,12 @@ let
};
virtualHost = mkOption {
- type = types.submodule ({
- options = import ../web-servers/apache-httpd/per-server-options.nix {
- inherit lib;
- forMainServer = false;
- };
- });
+ type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
example = literalExample ''
{
- enableSSL = true;
adminAddr = "webmaster@example.org";
- sslServerCert = "/var/lib/acme/wordpress.example.org/full.pem";
- sslServerKey = "/var/lib/acme/wordpress.example.org/key.pem";
+ forceSSL = true;
+ enableACME = true;
}
'';
description = ''
@@ -304,41 +298,37 @@ in
services.httpd = {
enable = true;
extraModules = [ "proxy_fcgi" ];
- virtualHosts = mapAttrsToList (hostName: cfg:
- (mkMerge [
- cfg.virtualHost {
- documentRoot = mkForce "${pkg hostName cfg}/share/wordpress";
- extraConfig = ''
-
-
-
- SetHandler "proxy:unix:${config.services.phpfpm.pools."wordpress-${hostName}".socket}|fcgi://localhost/"
-
-
+ virtualHosts = mapAttrs (hostName: cfg: mkMerge [ cfg.virtualHost {
+ documentRoot = mkForce "${pkg hostName cfg}/share/wordpress";
+ extraConfig = ''
+
+
+
+ SetHandler "proxy:unix:${config.services.phpfpm.pools."wordpress-${hostName}".socket}|fcgi://localhost/"
+
+
- # standard wordpress .htaccess contents
-
- RewriteEngine On
- RewriteBase /
- RewriteRule ^index\.php$ - [L]
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteCond %{REQUEST_FILENAME} !-d
- RewriteRule . /index.php [L]
-
+ # standard wordpress .htaccess contents
+
+ RewriteEngine On
+ RewriteBase /
+ RewriteRule ^index\.php$ - [L]
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteRule . /index.php [L]
+
- DirectoryIndex index.php
- Require all granted
- Options +FollowSymLinks
-
+ DirectoryIndex index.php
+ Require all granted
+ Options +FollowSymLinks
+
- # https://wordpress.org/support/article/hardening-wordpress/#securing-wp-config-php
-
- Require all denied
-
- '';
- }
- ])
- ) eachSite;
+ # https://wordpress.org/support/article/hardening-wordpress/#securing-wp-config-php
+
+ Require all denied
+
+ '';
+ } ]) eachSite;
};
systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
diff --git a/nixos/modules/services/web-apps/zabbix.nix b/nixos/modules/services/web-apps/zabbix.nix
index 09538726b7cd..ee8447810c6d 100644
--- a/nixos/modules/services/web-apps/zabbix.nix
+++ b/nixos/modules/services/web-apps/zabbix.nix
@@ -113,19 +113,15 @@ in
};
virtualHost = mkOption {
- type = types.submodule ({
- options = import ../web-servers/apache-httpd/per-server-options.nix {
- inherit lib;
- forMainServer = false;
- };
- });
- example = {
- hostName = "zabbix.example.org";
- enableSSL = true;
- adminAddr = "webmaster@example.org";
- sslServerCert = "/var/lib/acme/zabbix.example.org/full.pem";
- sslServerKey = "/var/lib/acme/zabbix.example.org/key.pem";
- };
+ type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ example = literalExample ''
+ {
+ hostName = "zabbix.example.org";
+ adminAddr = "webmaster@example.org";
+ forceSSL = true;
+ enableACME = true;
+ }
+ '';
description = ''
Apache configuration can be done by adapting services.httpd.virtualHosts.<name>.
See for further information.
@@ -190,23 +186,21 @@ in
enable = true;
adminAddr = mkDefault cfg.virtualHost.adminAddr;
extraModules = [ "proxy_fcgi" ];
- virtualHosts = [ (mkMerge [
- cfg.virtualHost {
- documentRoot = mkForce "${cfg.package}/share/zabbix";
- extraConfig = ''
-
-
-
- SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
-
-
- AllowOverride all
- Options -Indexes
- DirectoryIndex index.php
-
- '';
- }
- ]) ];
+ virtualHosts.${cfg.virtualHost.hostName} = mkMerge [ cfg.virtualHost {
+ documentRoot = mkForce "${cfg.package}/share/zabbix";
+ extraConfig = ''
+
+
+
+ SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
+
+
+ AllowOverride all
+ Options -Indexes
+ DirectoryIndex index.php
+
+ '';
+ } ];
};
users.users.${user} = mapAttrs (name: mkDefault) {
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 850d3052533a..8e3be3162988 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -18,22 +18,20 @@ let
mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; };
- defaultListen = cfg: if cfg.enableSSL
- then [{ip = "*"; port = 443;}]
- else [{ip = "*"; port = 80;}];
+ vhosts = attrValues mainCfg.virtualHosts;
- getListen = cfg:
- if cfg.listen == []
- then defaultListen cfg
- else cfg.listen;
+ 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; }
+ );
- listenToString = l: "${l.ip}:${toString l.port}";
+ listenInfo = unique (concatMap mkListenInfo vhosts);
- allHosts = [mainCfg] ++ mainCfg.virtualHosts;
+ enableSSL = any (listen: listen.ssl) listenInfo;
- enableSSL = any (vhost: vhost.enableSSL) allHosts;
-
- enableUserDir = any (vhost: vhost.enableUserDir) allHosts;
+ enableUserDir = any (vhost: vhost.enableUserDir) vhosts;
# NOTE: generally speaking order of modules is very important
modules =
@@ -115,122 +113,137 @@ let
'';
+ 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);
- perServerConf = isMainServer: cfg: let
+ 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.";
- # Canonical name must not include a trailing slash.
- canonicalNames =
- let defaultPort = (head (defaultListen cfg)).port; in
- map (port:
- (if cfg.enableSSL then "https" else "http") + "://" +
- cfg.hostName +
- (if port != defaultPort then ":${toString port}" else "")
- ) (map (x: x.port) (getListen cfg));
+ 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;
- maybeDocumentRoot = fold (svc: acc:
- if acc == null then svc.documentRoot else assert svc.documentRoot == null; acc
- ) null ([ cfg ]);
+ acmeChallenge = optionalString useACME ''
+ Alias /.well-known/acme-challenge/ "${hostOpts.acmeRoot}/.well-known/acme-challenge/"
+
+ AllowOverride None
+ Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+ Require method GET POST OPTIONS
+ Require all granted
+
+ '';
+ in
+ optionalString (listen != []) ''
+
+ ServerName ${hostOpts.hostName}
+ ${concatMapStrings (alias: "ServerAlias ${alias}\n") hostOpts.serverAliases}
+ ServerAdmin ${adminAddr}
+
+ SSLEngine off
+
+ ${acmeChallenge}
+ ${if hostOpts.forceSSL then ''
+
+ RewriteEngine on
+ RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge [NC]
+ RewriteCond %{HTTPS} off
+ RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
+
+ '' else mkVHostCommonConf hostOpts}
+
+ '' +
+ optionalString (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}
+
+ ''
+ ;
- documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else
- pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out";
+ 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}
+ ''}
- documentRootConf = ''
- DocumentRoot "${documentRoot}"
+ ${optionalString (hostOpts.robotsEntries != "") ''
+ Alias /robots.txt ${pkgs.writeText "robots.txt" hostOpts.robotsEntries}
+ ''}
-
- Options Indexes FollowSymLinks
- AllowOverride None
- ${allGranted}
-
- '';
+ DocumentRoot "${documentRoot}"
- # If this is a vhost, the include the entries for the main server as well.
- robotsTxt = concatStringsSep "\n" (filter (x: x != "") ([ cfg.robotsEntries ] ++ lib.optional (!isMainServer) mainCfg.robotsEntries));
+
+ Options Indexes FollowSymLinks
+ AllowOverride None
+ ${allGranted}
+
- in ''
- ${concatStringsSep "\n" (map (n: "ServerName ${n}") canonicalNames)}
+ ${optionalString hostOpts.enableUserDir ''
+ UserDir public_html
+ UserDir disabled root
+
+ AllowOverride FileInfo AuthConfig Limit Indexes
+ Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+
+ Require all granted
+
+
+ Require all denied
+
+
+ ''}
- ${concatMapStrings (alias: "ServerAlias ${alias}\n") cfg.serverAliases}
+ ${optionalString (hostOpts.globalRedirect != null && hostOpts.globalRedirect != "") ''
+ RedirectPermanent / ${hostOpts.globalRedirect}
+ ''}
- ${if cfg.sslServerCert != null then ''
- SSLCertificateFile ${cfg.sslServerCert}
- SSLCertificateKeyFile ${cfg.sslServerKey}
- ${if cfg.sslServerChain != null then ''
- SSLCertificateChainFile ${cfg.sslServerChain}
- '' else ""}
- '' else ""}
+ ${
+ let makeFileConf = elem: ''
+ Alias ${elem.urlPath} ${elem.file}
+ '';
+ in concatMapStrings makeFileConf hostOpts.servedFiles
+ }
+ ${
+ let makeDirConf = elem: ''
+ Alias ${elem.urlPath} ${elem.dir}/
+
+ Options +Indexes
+ ${allGranted}
+ AllowOverride All
+
+ '';
+ in concatMapStrings makeDirConf hostOpts.servedDirs
+ }
- ${if cfg.enableSSL then ''
- SSLEngine on
- '' else if enableSSL then /* i.e., SSL is enabled for some host, but not this one */
- ''
- SSLEngine off
- '' else ""}
-
- ${if isMainServer || cfg.adminAddr != null then ''
- ServerAdmin ${cfg.adminAddr}
- '' else ""}
-
- ${if !isMainServer && mainCfg.logPerVirtualHost then ''
- ErrorLog ${mainCfg.logDir}/error-${cfg.hostName}.log
- CustomLog ${mainCfg.logDir}/access-${cfg.hostName}.log ${cfg.logFormat}
- '' else ""}
-
- ${optionalString (robotsTxt != "") ''
- Alias /robots.txt ${pkgs.writeText "robots.txt" robotsTxt}
- ''}
-
- ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""}
-
- ${if cfg.enableUserDir then ''
-
- UserDir public_html
- UserDir disabled root
-
-
- AllowOverride FileInfo AuthConfig Limit Indexes
- Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
-
- ${allGranted}
-
-
- ${allDenied}
-
-
-
- '' else ""}
-
- ${if cfg.globalRedirect != null && cfg.globalRedirect != "" then ''
- RedirectPermanent / ${cfg.globalRedirect}
- '' else ""}
-
- ${
- let makeFileConf = elem: ''
- Alias ${elem.urlPath} ${elem.file}
- '';
- in concatMapStrings makeFileConf cfg.servedFiles
- }
-
- ${
- let makeDirConf = elem: ''
- Alias ${elem.urlPath} ${elem.dir}/
-
- Options +Indexes
- ${allGranted}
- AllowOverride All
-
- '';
- in concatMapStrings makeDirConf cfg.servedDirs
- }
-
- ${cfg.extraConfig}
- '';
+ ${hostOpts.extraConfig}
+ ''
+ ;
confFile = pkgs.writeText "httpd.conf" ''
ServerRoot ${httpd}
-
+ ServerName ${config.networking.hostName}
DefaultRuntimeDir ${runtimeDir}/runtime
PidFile ${runtimeDir}/httpd.pid
@@ -246,10 +259,9 @@ let
${let
- listen = concatMap getListen allHosts;
- toStr = listen: "Listen ${listenToString listen}\n";
- uniqueListen = uniqList {inputList = map toStr listen;};
- in concatStrings uniqueListen
+ 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
}
User ${mainCfg.user}
@@ -297,17 +309,9 @@ let
${allGranted}
- # Generate directives for the main server.
- ${perServerConf true mainCfg}
+ ${mainCfg.extraConfig}
- ${let
- makeVirtualHost = vhost: ''
-
- ${perServerConf false vhost}
-
- '';
- in concatMapStrings makeVirtualHost mainCfg.virtualHosts
- }
+ ${concatMapStringsSep "\n" mkVHostConf vhosts}
'';
# Generate the PHP configuration file. Should probably be factored
@@ -329,6 +333,21 @@ in
imports = [
(mkRemovedOptionModule [ "services" "httpd" "extraSubservices" ] "Most existing subservices have been ported to the NixOS module system. Please update your configuration accordingly.")
(mkRemovedOptionModule [ "services" "httpd" "stateDir" ] "The httpd module now uses /run/httpd as a runtime directory.")
+
+ # 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`.")
];
###### interface
@@ -391,9 +410,25 @@ in
'';
};
+ 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 for more details.
+ '';
+ };
+
logPerVirtualHost = mkOption {
type = types.bool;
- default = false;
+ default = true;
description = ''
If enabled, each virtual host gets its own
access.log and
@@ -429,26 +464,28 @@ in
};
virtualHosts = mkOption {
- type = types.listOf (types.submodule (
- { options = import ./per-server-options.nix {
- inherit lib;
- forMainServer = false;
+ 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";
};
- }));
- default = [];
- example = [
- { hostName = "foo";
- documentRoot = "/data/webroot-foo";
}
- { hostName = "bar";
- documentRoot = "/data/webroot-bar";
- }
- ];
+ '';
description = ''
- Specification of the virtual hosts served by Apache. Each
+ Specification of the virtual hosts served by Apache. Each
element should be an attribute set specifying the
- configuration of the virtual host. The available options
- are the non-global options permissible for the main host.
+ configuration of the virtual host.
'';
};
@@ -534,13 +571,7 @@ in
example = "All -SSLv2 -SSLv3";
description = "Allowed SSL/TLS protocol versions.";
};
- }
-
- # Include the options shared between the main server and virtual hosts.
- // (import ./per-server-options.nix {
- inherit lib;
- forMainServer = true;
- });
+ };
};
@@ -549,11 +580,31 @@ in
config = mkIf config.services.httpd.enable {
- assertions = [ { assertion = mainCfg.enableSSL == true
- -> mainCfg.sslServerCert != null
- && mainCfg.sslServerKey != null;
- message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; }
- ];
+ assertions = [
+ {
+ assertion = all (hostOpts: !hostOpts.enableSSL) vhosts;
+ message = ''
+ The option `services.httpd.virtualHosts..enableSSL` no longer has any effect; please remove it.
+ Select one of `services.httpd.virtualHosts..addSSL`, `services.httpd.virtualHosts..forceSSL`,
+ or `services.httpd.virtualHosts..onlySSL`.
+ '';
+ }
+ {
+ assertion = all (hostOpts: with hostOpts; !(addSSL && onlySSL) && !(forceSSL && onlySSL) && !(addSSL && forceSSL)) vhosts;
+ message = ''
+ Options `services.httpd.virtualHosts..addSSL`,
+ `services.httpd.virtualHosts..onlySSL` and `services.httpd.virtualHosts..forceSSL`
+ are mutually exclusive.
+ '';
+ }
+ {
+ assertion = all (hostOpts: !(hostOpts.enableACME && hostOpts.useACMEHost != null)) vhosts;
+ message = ''
+ Options `services.httpd.virtualHosts..enableACME` and
+ `services.httpd.virtualHosts..useACMEHost` are mutually exclusive.
+ '';
+ }
+ ];
users.users = optionalAttrs (mainCfg.user == "wwwrun") (singleton
{ name = "wwwrun";
@@ -567,6 +618,15 @@ in
gid = config.ids.gids.wwwrun;
});
+ 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);
+
environment.systemPackages = [httpd];
services.httpd.phpOptions =
@@ -605,10 +665,14 @@ in
];
systemd.services.httpd =
+ let
+ vhostsACME = filter (hostOpts: hostOpts.enableACME) vhosts;
+ in
{ description = "Apache HTTPD";
wantedBy = [ "multi-user.target" ];
- after = [ "network.target" "fs.target" ];
+ 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;
path =
[ httpd pkgs.coreutils pkgs.gnugrep ]
diff --git a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
index c36207d54607..f2e92cda05f6 100644
--- a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
@@ -1,174 +1,235 @@
-# This file defines the options that can be used both for the Apache
-# main server configuration, and for the virtual hosts. (The latter
-# has additional options that affect the web server as a whole, like
-# the user/group to run under.)
-
-{ forMainServer, lib }:
-
-with lib;
-
+{ config, lib, name, ... }:
+let
+ inherit (lib) mkOption types;
+in
{
+ options = {
+
+ hostName = mkOption {
+ type = types.str;
+ default = name;
+ description = "Canonical hostname for the server.";
+ };
+
+ serverAliases = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = ["www.example.org" "www.example.org:8080" "example.org"];
+ description = ''
+ Additional names of virtual hosts served by this virtual host configuration.
+ '';
+ };
+
+ listen = mkOption {
+ type = with types; listOf (submodule ({
+ options = {
+ port = mkOption {
+ type = types.port;
+ description = "Port to listen on";
+ };
+ ip = mkOption {
+ type = types.str;
+ default = "*";
+ description = "IP to listen on. 0.0.0.0 for IPv4 only, * for all.";
+ };
+ ssl = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Whether to enable SSL (https) support.";
+ };
+ };
+ }));
+ default = [];
+ example = [
+ { ip = "195.154.1.1"; port = 443; ssl = true;}
+ { ip = "192.154.1.1"; port = 80; }
+ { ip = "*"; port = 8080; }
+ ];
+ description = ''
+ Listen addresses and ports for this virtual host.
+
+ This option overrides addSSL, forceSSL and onlySSL.
+
+ '';
+ };
+
+ enableSSL = mkOption {
+ type = types.bool;
+ visible = false;
+ default = false;
+ };
+
+ addSSL = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable HTTPS in addition to plain HTTP. This will set defaults for
+ listen to listen on all interfaces on the respective default
+ ports (80, 443).
+ '';
+ };
+
+ onlySSL = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable HTTPS and reject plain HTTP connections. This will set
+ defaults for listen to listen on all interfaces on port 443.
+ '';
+ };
+
+ forceSSL = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to add a separate nginx server block that permanently redirects (301)
+ all plain HTTP traffic to HTTPS. This will set defaults for
+ listen to listen on all interfaces on the respective default
+ ports (80, 443), where the non-SSL listens are used for the redirect vhosts.
+ '';
+ };
+
+ enableACME = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to ask Let's Encrypt to sign a certificate for this vhost.
+ Alternately, you can use an existing certificate through .
+ '';
+ };
+
+ useACMEHost = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ A host of an existing Let's Encrypt certificate to use.
+ This is useful if you have many subdomains and want to avoid hitting the
+ rate limit.
+ Alternately, you can generate a certificate through .
+ Note that this option does not create any certificates, nor it does add subdomains to existing ones – you will need to create them manually using .
+ '';
+ };
+
+ acmeRoot = mkOption {
+ type = types.str;
+ default = "/var/lib/acme/acme-challenges";
+ description = "Directory for the acme challenge which is PUBLIC, don't put certs or keys in here";
+ };
+
+ sslServerCert = mkOption {
+ type = types.path;
+ example = "/var/host.cert";
+ description = "Path to server SSL certificate.";
+ };
+
+ sslServerKey = mkOption {
+ type = types.path;
+ example = "/var/host.key";
+ description = "Path to server SSL certificate key.";
+ };
+
+ sslServerChain = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ example = "/var/ca.pem";
+ description = "Path to server SSL chain file.";
+ };
+
+ adminAddr = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "admin@example.org";
+ description = "E-mail address of the server administrator.";
+ };
+
+ documentRoot = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ example = "/data/webserver/docs";
+ description = ''
+ The path of Apache's document root directory. If left undefined,
+ an empty directory in the Nix store will be used as root.
+ '';
+ };
+
+ servedDirs = mkOption {
+ type = types.listOf types.attrs;
+ default = [];
+ example = [
+ { urlPath = "/nix";
+ dir = "/home/eelco/Dev/nix-homepage";
+ }
+ ];
+ description = ''
+ This option provides a simple way to serve static directories.
+ '';
+ };
+
+ servedFiles = mkOption {
+ type = types.listOf types.attrs;
+ default = [];
+ example = [
+ { urlPath = "/foo/bar.png";
+ file = "/home/eelco/some-file.png";
+ }
+ ];
+ description = ''
+ This option provides a simple way to serve individual, static files.
+ '';
+ };
+
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ example = ''
+
+ Options FollowSymlinks
+ AllowOverride All
+
+ '';
+ description = ''
+ These lines go to httpd.conf verbatim. They will go after
+ directories and directory aliases defined by default.
+ '';
+ };
+
+ enableUserDir = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable serving ~/public_html as
+ /~username.
+ '';
+ };
+
+ globalRedirect = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = http://newserver.example.org/;
+ description = ''
+ If set, all requests for this host are redirected permanently to
+ the given URL.
+ '';
+ };
+
+ logFormat = mkOption {
+ type = types.str;
+ default = "common";
+ example = "combined";
+ description = ''
+ Log format for Apache's log files. Possible values are: combined, common, referer, agent.
+ '';
+ };
+
+ robotsEntries = mkOption {
+ type = types.lines;
+ default = "";
+ example = "Disallow: /foo/";
+ description = ''
+ Specification of pages to be ignored by web crawlers. See for details.
+ '';
+ };
- hostName = mkOption {
- type = types.str;
- default = "localhost";
- description = "Canonical hostname for the server.";
};
-
- serverAliases = mkOption {
- type = types.listOf types.str;
- default = [];
- example = ["www.example.org" "www.example.org:8080" "example.org"];
- description = ''
- Additional names of virtual hosts served by this virtual host configuration.
- '';
- };
-
- listen = mkOption {
- type = types.listOf (types.submodule (
- {
- options = {
- port = mkOption {
- type = types.int;
- description = "port to listen on";
- };
- ip = mkOption {
- type = types.str;
- default = "*";
- description = "Ip to listen on. 0.0.0.0 for ipv4 only, * for all.";
- };
- };
- } ));
- description = ''
- List of { /* ip: "*"; */ port = 80;} to listen on
- '';
-
- default = [];
- };
-
- enableSSL = mkOption {
- type = types.bool;
- default = false;
- description = "Whether to enable SSL (https) support.";
- };
-
- # Note: sslServerCert and sslServerKey can be left empty, but this
- # only makes sense for virtual hosts (they will inherit from the
- # main server).
-
- sslServerCert = mkOption {
- type = types.nullOr types.path;
- default = null;
- example = "/var/host.cert";
- description = "Path to server SSL certificate.";
- };
-
- sslServerKey = mkOption {
- type = types.path;
- example = "/var/host.key";
- description = "Path to server SSL certificate key.";
- };
-
- sslServerChain = mkOption {
- type = types.nullOr types.path;
- default = null;
- example = "/var/ca.pem";
- description = "Path to server SSL chain file.";
- };
-
- adminAddr = mkOption ({
- type = types.nullOr types.str;
- example = "admin@example.org";
- description = "E-mail address of the server administrator.";
- } // (if forMainServer then {} else {default = null;}));
-
- documentRoot = mkOption {
- type = types.nullOr types.path;
- default = null;
- example = "/data/webserver/docs";
- description = ''
- The path of Apache's document root directory. If left undefined,
- an empty directory in the Nix store will be used as root.
- '';
- };
-
- servedDirs = mkOption {
- type = types.listOf types.attrs;
- default = [];
- example = [
- { urlPath = "/nix";
- dir = "/home/eelco/Dev/nix-homepage";
- }
- ];
- description = ''
- This option provides a simple way to serve static directories.
- '';
- };
-
- servedFiles = mkOption {
- type = types.listOf types.attrs;
- default = [];
- example = [
- { urlPath = "/foo/bar.png";
- file = "/home/eelco/some-file.png";
- }
- ];
- description = ''
- This option provides a simple way to serve individual, static files.
- '';
- };
-
- extraConfig = mkOption {
- type = types.lines;
- default = "";
- example = ''
-
- Options FollowSymlinks
- AllowOverride All
-
- '';
- description = ''
- These lines go to httpd.conf verbatim. They will go after
- directories and directory aliases defined by default.
- '';
- };
-
- enableUserDir = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to enable serving ~/public_html as
- /~username.
- '';
- };
-
- globalRedirect = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = http://newserver.example.org/;
- description = ''
- If set, all requests for this host are redirected permanently to
- the given URL.
- '';
- };
-
- logFormat = mkOption {
- type = types.str;
- default = "common";
- example = "combined";
- description = ''
- Log format for Apache's log files. Possible values are: combined, common, referer, agent.
- '';
- };
-
- robotsEntries = mkOption {
- type = types.lines;
- default = "";
- example = "Disallow: /foo/";
- description = ''
- Specification of pages to be ignored by web crawlers. See for details.
- '';
- };
-
}
diff --git a/nixos/tests/ec2.nix b/nixos/tests/ec2.nix
index 384fce67c227..c649ce852dad 100644
--- a/nixos/tests/ec2.nix
+++ b/nixos/tests/ec2.nix
@@ -113,7 +113,7 @@ in {
services.httpd = {
enable = true;
adminAddr = "test@example.org";
- documentRoot = "${pkgs.valgrind.doc}/share/doc/valgrind/html";
+ virtualHosts.localhost.documentRoot = "${pkgs.valgrind.doc}/share/doc/valgrind/html";
};
networking.firewall.allowedTCPPorts = [ 80 ];
}
diff --git a/nixos/tests/haproxy.nix b/nixos/tests/haproxy.nix
index b6fed3e2108f..79f34b07faf4 100644
--- a/nixos/tests/haproxy.nix
+++ b/nixos/tests/haproxy.nix
@@ -23,12 +23,14 @@ import ./make-test-python.nix ({ pkgs, ...}: {
};
services.httpd = {
enable = true;
- documentRoot = pkgs.writeTextDir "index.txt" "We are all good!";
- adminAddr = "notme@yourhost.local";
- listen = [{
- ip = "::1";
- port = 8000;
- }];
+ virtualHosts.localhost = {
+ documentRoot = pkgs.writeTextDir "index.txt" "We are all good!";
+ adminAddr = "notme@yourhost.local";
+ listen = [{
+ ip = "::1";
+ port = 8000;
+ }];
+ };
};
};
};
diff --git a/nixos/tests/hitch/default.nix b/nixos/tests/hitch/default.nix
index 106120256412..904d12619d70 100644
--- a/nixos/tests/hitch/default.nix
+++ b/nixos/tests/hitch/default.nix
@@ -16,7 +16,7 @@ import ../make-test-python.nix ({ pkgs, ... }:
services.httpd = {
enable = true;
- documentRoot = ./example;
+ virtualHosts.localhost.documentRoot = ./example;
adminAddr = "noone@testing.nowhere";
};
};
diff --git a/nixos/tests/proxy.nix b/nixos/tests/proxy.nix
index 1f39e903cddb..3859d429c21b 100644
--- a/nixos/tests/proxy.nix
+++ b/nixos/tests/proxy.nix
@@ -1,4 +1,4 @@
-import ./make-test.nix ({ pkgs, ...} :
+import ./make-test.nix ({ pkgs, ...} :
let
@@ -7,7 +7,7 @@ let
{ services.httpd.enable = true;
services.httpd.adminAddr = "foo@example.org";
- services.httpd.documentRoot = "${pkgs.valgrind.doc}/share/doc/valgrind/html";
+ services.httpd.virtualHosts.localhost.documentRoot = "${pkgs.valgrind.doc}/share/doc/valgrind/html";
networking.firewall.allowedTCPPorts = [ 80 ];
};
@@ -26,11 +26,11 @@ in
{ services.httpd.enable = true;
services.httpd.adminAddr = "bar@example.org";
services.httpd.extraModules = [ "proxy_balancer" "lbmethod_byrequests" ];
-
- services.httpd.extraConfig =
- ''
- ExtendedStatus on
-
+ services.httpd.extraConfig = ''
+ ExtendedStatus on
+ '';
+ services.httpd.virtualHosts.localhost = {
+ extraConfig = ''
Require all granted
SetHandler server-status
@@ -50,6 +50,7 @@ in
# For testing; don't want to wait forever for dead backend servers.
ProxyTimeout 5
'';
+ };
networking.firewall.allowedTCPPorts = [ 80 ];
};
diff --git a/nixos/tests/upnp.nix b/nixos/tests/upnp.nix
index d2e7fdd4fbeb..a7d837ea0708 100644
--- a/nixos/tests/upnp.nix
+++ b/nixos/tests/upnp.nix
@@ -56,9 +56,11 @@ in
networking.firewall.enable = false;
services.httpd.enable = true;
- services.httpd.listen = [{ ip = "*"; port = 9000; }];
- services.httpd.adminAddr = "foo@example.org";
- services.httpd.documentRoot = "/tmp";
+ services.httpd.virtualHosts.localhost = {
+ listen = [{ ip = "*"; port = 9000; }];
+ adminAddr = "foo@example.org";
+ documentRoot = "/tmp";
+ };
};
client2 =