* Support for declaring virtual hosts, like

httpd = {
      ...
      virtualHosts = [
        { hostName = "foo";
          documentRoot = "/data/webroot-foo";
          ...
        }
        { hostName = "bar";
          documentRoot = "/data/webroot-bar";
          ...
        }
      ];
    };

  Each virtual host can specify almost any option also permitted in
  the top-level httpd configuration.

svn path=/nixos/trunk/; revision=10682
This commit is contained in:
Eelco Dolstra 2008-02-14 13:20:26 +00:00
parent bfbe92236a
commit 94937ba2aa
4 changed files with 185 additions and 119 deletions

View File

@ -1194,13 +1194,6 @@
"; ";
}; };
adminAddr = mkOption {
example = "admin@example.org";
description = "
E-mail address of the server administrator.
";
};
logDir = mkOption { logDir = mkOption {
default = "/var/log/httpd"; default = "/var/log/httpd";
description = " description = "
@ -1225,54 +1218,6 @@
"; ";
}; };
documentRoot = mkOption {
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 {
default = [];
example = [
{ urlPath = "/nix";
dir = "/home/eelco/Dev/nix-homepage";
}
];
description = "
This option provides a simple way to serve static directories.
";
};
servedFiles = mkOption {
default = [];
example = [
{ urlPath = "/foo/bar.png";
dir = "/home/eelco/some-file.png";
}
];
description = "
This option provides a simple way to serve individual, static files.
";
};
# !!! this is a mis-nomer, should be "extraConfig" or something.
extraDirectories = mkOption {
default = "";
example = "
<Directory /home>
Options FollowSymlinks
AllowOverride All
</Directory>
";
description = "
These lines go to httpd.conf verbatim. They will go after
directories and directory aliases defined by default.
";
};
mod_php = mkOption { mod_php = mkOption {
default = false; default = false;
description = "Whether to enable the PHP module."; description = "Whether to enable the PHP module.";
@ -1367,14 +1312,11 @@
}; };
extraSubservices = mkOption { } // # Include the options shared between the main server and virtual hosts.
default = []; (import ../upstart-jobs/apache-httpd/per-server-options.nix {
description = " inherit mkOption;
Extra subservices to enable in the webserver. forMainServer = true;
"; });
};
};
vsftpd = { vsftpd = {
enable = mkOption { enable = mkOption {

View File

@ -9,23 +9,25 @@ let
httpd = pkgs.apacheHttpd; httpd = pkgs.apacheHttpd;
serverInfo = { makeServerInfo = cfg: {
# Canonical name must not include a trailing slash. # Canonical name must not include a trailing slash.
canonicalName = canonicalName =
"http://" + "http://${cfg.hostName}" +
cfg.hostName +
(if cfg.httpPort != 80 then ":${toString cfg.httpPort}" else ""); (if cfg.httpPort != 80 then ":${toString cfg.httpPort}" else "");
serverConfig = cfg; serverConfig = cfg;
fullConfig = config; # machine config fullConfig = config; # machine config
}; };
subservices = callSubservices = serverInfo: defs:
let f = svc: let f = svc:
let config = pkgs.lib.addDefaultOptionValues res.options svc.config; let config = pkgs.lib.addDefaultOptionValues res.options svc.config;
res = svc.function {inherit config pkgs serverInfo;}; res = svc.function {inherit config pkgs serverInfo;};
in res; in res;
in map f cfg.extraSubservices; in map f defs;
allSubservices = callSubservices (makeServerInfo cfg) cfg.extraSubservices;
# !!! should be in lib # !!! should be in lib
@ -33,10 +35,6 @@ let
pkgs.runCommand name {inherit text;} "ensureDir $out; echo -n \"$text\" > $out/$name"; pkgs.runCommand name {inherit text;} "ensureDir $out; echo -n \"$text\" > $out/$name";
documentRoot = if cfg.documentRoot != null then cfg.documentRoot else
pkgs.runCommand "empty" {} "ensureDir $out";
# Names of modules from ${httpd}/modules that we want to load. # Names of modules from ${httpd}/modules that we want to load.
apacheModules = apacheModules =
[ # HTTP authentication mechanisms: basic and digest. [ # HTTP authentication mechanisms: basic and digest.
@ -84,6 +82,7 @@ let
''; '';
# !!! integrate with virtual hosting below
sslConf = '' sslConf = ''
Listen ${toString cfg.httpsPort} Listen ${toString cfg.httpsPort}
@ -128,6 +127,15 @@ let
''; '';
perServerConf = isMainServer: cfg: let
serverInfo = makeServerInfo cfg;
subservices = callSubservices serverInfo cfg.extraSubservices;
documentRoot = if cfg.documentRoot != null then cfg.documentRoot else
pkgs.runCommand "empty" {} "ensureDir $out";
documentRootConf = '' documentRootConf = ''
DocumentRoot "${documentRoot}" DocumentRoot "${documentRoot}"
@ -139,24 +147,52 @@ let
</Directory> </Directory>
''; '';
robotsTxt = pkgs.writeText "robots.txt" '' robotsTxt = pkgs.writeText "robots.txt" ''
${pkgs.lib.concatStrings (map (svc: svc.robotsEntries) subservices)} ${concatMapStrings (svc: svc.robotsEntries) subservices}
''; '';
robotsConf = '' robotsConf = ''
Alias /robots.txt ${robotsTxt} Alias /robots.txt ${robotsTxt}
''; '';
in ''
ServerName ${serverInfo.canonicalName}
${if isMainServer || cfg.adminAddr != "" then ''
ServerAdmin ${cfg.adminAddr}
'' else ""}
${robotsConf}
${if isMainServer || cfg.documentRoot != null then documentRootConf else ""}
${
let makeDirConf = elem: ''
Alias ${elem.urlPath} ${elem.dir}/
<Directory ${elem.dir}>
Order allow,deny
Allow from all
AllowOverride None
</Directory>
'';
in concatMapStrings makeDirConf cfg.servedDirs
}
${
let makeFileConf = elem: ''
Alias ${elem.urlPath} ${elem.file}
'';
in concatMapStrings makeFileConf cfg.servedFiles
}
${concatMapStrings (svc: svc.extraConfig) subservices}
'';
httpdConf = pkgs.writeText "httpd.conf" '' httpdConf = pkgs.writeText "httpd.conf" ''
ServerRoot ${httpd} ServerRoot ${httpd}
ServerAdmin ${cfg.adminAddr}
ServerName ${serverInfo.canonicalName}
PidFile ${cfg.stateDir}/httpd.pid PidFile ${cfg.stateDir}/httpd.pid
<IfModule prefork.c> <IfModule prefork.c>
@ -172,10 +208,10 @@ let
${let ${let
load = {name, path}: "LoadModule ${name}_module ${path}\n"; load = {name, path}: "LoadModule ${name}_module ${path}\n";
allModules = allModules =
pkgs.lib.concatMap (svc: svc.extraModulesPre) subservices ++ pkgs.lib.concatMap (svc: svc.extraModulesPre) allSubservices ++
map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules ++
pkgs.lib.concatMap (svc: svc.extraModules) subservices; pkgs.lib.concatMap (svc: svc.extraModules) allSubservices;
in pkgs.lib.concatStrings (map load allModules) in concatMapStrings load allModules
} }
${if cfg.enableUserDir then '' ${if cfg.enableUserDir then ''
@ -232,30 +268,32 @@ let
Allow from all Allow from all
</Directory> </Directory>
${robotsConf} # Generate directives for the main server.
${perServerConf true cfg}
${documentRootConf} # Always enable virtual hosts; it doesn't seem to hurt.
NameVirtualHost *:*
${ # Catch-all: since this is the first virtual host, any
let makeDirConf = elem: '' # non-matching requests will use the main server configuration.
Alias ${elem.urlPath} ${elem.dir}/ <VirtualHost *:*>
<Directory ${elem.dir}> </VirtualHost>
Order allow,deny
Allow from all ${let
AllowOverride None perServerOptions = import ./per-server-options.nix {
</Directory> inherit (pkgs.lib) mkOption;
forMainServer = false;
};
makeVirtualHost = vhostIn:
let
# Fill in defaults for missing options.
vhost = pkgs.lib.addDefaultOptionValues perServerOptions vhostIn;
in ''
<VirtualHost *:*>
${perServerConf false vhost}
</VirtualHost>
''; '';
in pkgs.lib.concatStrings (map makeDirConf cfg.servedDirs) in concatMapStrings makeVirtualHost cfg.virtualHosts}
}
${
let makeFileConf = elem: ''
Alias ${elem.urlPath} ${elem.file}
'';
in pkgs.lib.concatStrings (map makeFileConf cfg.servedFiles)
}
${pkgs.lib.concatStrings (map (svc: svc.extraConfig) subservices)}
''; '';
@ -276,7 +314,7 @@ in
} }
]; ];
extraPath = [httpd] ++ pkgs.lib.concatMap (svc: svc.extraPath) subservices; extraPath = [httpd] ++ pkgs.lib.concatMap (svc: svc.extraPath) allSubservices;
# Statically verify the syntactic correctness of the generated # Statically verify the syntactic correctness of the generated
# httpd.conf. # httpd.conf.
@ -306,10 +344,10 @@ in
${ ${
let f = {name, value}: "env ${name}=${value}\n"; let f = {name, value}: "env ${name}=${value}\n";
in pkgs.lib.concatStrings (map f (pkgs.lib.concatMap (svc: svc.globalEnvVars) subservices)) in pkgs.lib.concatStrings (map f (pkgs.lib.concatMap (svc: svc.globalEnvVars) allSubservices))
} }
env PATH=${pkgs.coreutils}/bin:${pkgs.gnugrep}/bin:${pkgs.lib.concatStringsSep ":" (pkgs.lib.concatMap (svc: svc.extraServerPath) subservices)} env PATH=${pkgs.coreutils}/bin:${pkgs.gnugrep}/bin:${pkgs.lib.concatStringsSep ":" (pkgs.lib.concatMap (svc: svc.extraServerPath) allSubservices)}
${pkgs.diffutils}/bin:${pkgs.gnused}/bin ${pkgs.diffutils}/bin:${pkgs.gnused}/bin

View File

@ -0,0 +1,86 @@
# 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, mkOption}:
{
hostName = mkOption {
default = "localhost";
description = "
Canonical hostname for the server.
";
};
httpPort = mkOption {
default = 80;
description = "
Port for unencrypted HTTP requests.
";
};
adminAddr = mkOption ({
example = "admin@example.org";
description = "
E-mail address of the server administrator.
";
} // (if forMainServer then {} else {default = "";}));
documentRoot = mkOption {
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 {
default = [];
example = [
{ urlPath = "/nix";
dir = "/home/eelco/Dev/nix-homepage";
}
];
description = "
This option provides a simple way to serve static directories.
";
};
servedFiles = mkOption {
default = [];
example = [
{ urlPath = "/foo/bar.png";
dir = "/home/eelco/some-file.png";
}
];
description = "
This option provides a simple way to serve individual, static files.
";
};
# !!! this is a mis-nomer, should be "extraConfig" or something.
extraDirectories = mkOption {
default = "";
example = "
<Directory /home>
Options FollowSymlinks
AllowOverride All
</Directory>
";
description = "
These lines go to httpd.conf verbatim. They will go after
directories and directory aliases defined by default.
";
};
extraSubservices = mkOption {
default = [];
description = "
Extra subservices to enable in the webserver.
";
};
}