caddy: add virtualHosts stub

Changed files
+114 -40
nixos
modules
services
web-servers
tests
+1 -1
nixos/modules/module-list.nix
···
./services/web-apps/youtrack.nix
./services/web-apps/zabbix.nix
./services/web-servers/apache-httpd/default.nix
-
./services/web-servers/caddy.nix
+
./services/web-servers/caddy/default.nix
./services/web-servers/darkhttpd.nix
./services/web-servers/fcgiwrap.nix
./services/web-servers/hitch/default.nix
+33 -2
nixos/modules/services/web-servers/caddy.nix nixos/modules/services/web-servers/caddy/default.nix
···
let
cfg = config.services.caddy;
-
configFile = pkgs.writeText "Caddyfile" cfg.config;
+
vhostToConfig = vhostName: vhostAttrs: ''
+
${vhostName} ${builtins.concatStringsSep " " vhostAttrs.serverAliases} {
+
${vhostAttrs.extraConfig}
+
}
+
'';
+
configFile = pkgs.writeText "Caddyfile" (builtins.concatStringsSep "\n"
+
([ cfg.config ] ++ (mapAttrsToList vhostToConfig cfg.virtualHosts)));
+
+
formattedConfig = pkgs.runCommand "formattedCaddyFile" { } ''
+
${cfg.package}/bin/caddy fmt ${configFile} > $out
+
'';
tlsConfig = {
apps.tls.automation.policies = [{
···
adaptedConfig = pkgs.runCommand "caddy-config-adapted.json" { } ''
${cfg.package}/bin/caddy adapt \
-
--config ${configFile} --adapter ${cfg.adapter} > $out
+
--config ${formattedConfig} --adapter ${cfg.adapter} > $out
'';
tlsJSON = pkgs.writeText "tls.json" (builtins.toJSON tlsConfig);
···
Caddy v2 supports multiple config formats via adapters (see <option>services.caddy.adapter</option>).
'';
};
+
+
virtualHosts = mkOption {
+
type = types.attrsOf (types.submodule (import ./vhost-options.nix {
+
inherit config lib;
+
}));
+
default = { };
+
example = literalExample ''
+
{
+
"hydra.example.com" = {
+
serverAliases = [ "www.hydra.example.com" ];
+
extraConfig = ''''''
+
encode gzip
+
log
+
root /srv/http
+
'''''';
+
};
+
};
+
'';
+
description = "Declarative vhost config";
+
};
+
user = mkOption {
default = "caddy";
+28
nixos/modules/services/web-servers/caddy/vhost-options.nix
···
+
# This file defines the options that can be used both for the Nginx
+
# 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.)
+
+
{ lib, ... }:
+
+
with lib;
+
{
+
options = {
+
serverAliases = mkOption {
+
type = types.listOf types.str;
+
default = [ ];
+
example = [ "www.example.org" "example.org" ];
+
description = ''
+
Additional names of virtual hosts served by this virtual host configuration.
+
'';
+
};
+
+
extraConfig = mkOption {
+
type = types.lines;
+
default = "";
+
description = ''
+
These lines go into the vhost verbatim
+
'';
+
};
+
};
+
}
+52 -37
nixos/tests/caddy.nix
···
}
'';
};
+
specialisation.multiple-configs.configuration = {
+
services.caddy.virtualHosts = {
+
"http://localhost:8080" = { };
+
"http://localhost:8081" = { };
+
};
+
};
};
-
};
-
testScript = { nodes, ... }: let
-
etagSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/etag";
-
justReloadSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/config-reload";
-
in ''
-
url = "http://localhost/example.html"
-
webserver.wait_for_unit("caddy")
-
webserver.wait_for_open_port("80")
+
testScript = { nodes, ... }:
+
let
+
etagSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/etag";
+
justReloadSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/config-reload";
+
multipleConfigs = "${nodes.webserver.config.system.build.toplevel}/specialisation/multiple-configs";
+
in
+
''
+
url = "http://localhost/example.html"
+
webserver.wait_for_unit("caddy")
+
webserver.wait_for_open_port("80")
-
def check_etag(url):
-
etag = webserver.succeed(
-
"curl --fail -v '{}' 2>&1 | sed -n -e \"s/^< [Ee][Tt][Aa][Gg]: *//p\"".format(
-
url
+
def check_etag(url):
+
etag = webserver.succeed(
+
"curl --fail -v '{}' 2>&1 | sed -n -e \"s/^< [Ee][Tt][Aa][Gg]: *//p\"".format(
+
url
+
)
)
-
)
-
etag = etag.replace("\r\n", " ")
-
http_code = webserver.succeed(
-
"curl --fail --silent --show-error -o /dev/null -w \"%{{http_code}}\" --head -H 'If-None-Match: {}' {}".format(
-
etag, url
+
etag = etag.replace("\r\n", " ")
+
http_code = webserver.succeed(
+
"curl --fail --silent --show-error -o /dev/null -w \"%{{http_code}}\" --head -H 'If-None-Match: {}' {}".format(
+
etag, url
+
)
)
-
)
-
assert int(http_code) == 304, "HTTP code is {}, expected 304".format(http_code)
-
return etag
+
assert int(http_code) == 304, "HTTP code is {}, expected 304".format(http_code)
+
return etag
-
with subtest("check ETag if serving Nix store paths"):
-
old_etag = check_etag(url)
-
webserver.succeed(
-
"${etagSystem}/bin/switch-to-configuration test >&2"
-
)
-
webserver.sleep(1)
-
new_etag = check_etag(url)
-
assert old_etag != new_etag, "Old ETag {} is the same as {}".format(
-
old_etag, new_etag
-
)
+
with subtest("check ETag if serving Nix store paths"):
+
old_etag = check_etag(url)
+
webserver.succeed(
+
"${etagSystem}/bin/switch-to-configuration test >&2"
+
)
+
webserver.sleep(1)
+
new_etag = check_etag(url)
+
assert old_etag != new_etag, "Old ETag {} is the same as {}".format(
+
old_etag, new_etag
+
)
-
with subtest("config is reloaded on nixos-rebuild switch"):
-
webserver.succeed(
-
"${justReloadSystem}/bin/switch-to-configuration test >&2"
-
)
-
webserver.wait_for_open_port("8080")
-
'';
-
})
+
with subtest("config is reloaded on nixos-rebuild switch"):
+
webserver.succeed(
+
"${justReloadSystem}/bin/switch-to-configuration test >&2"
+
)
+
webserver.wait_for_open_port("8080")
+
+
with subtest("multiple configs are correctly merged"):
+
webserver.succeed(
+
"${multipleConfigs}/bin/switch-to-configuration test >&2"
+
)
+
webserver.wait_for_open_port("8080")
+
webserver.wait_for_open_port("8081")
+
'';
+
})