nixos/h2o: enable HTTP/3 via QUIC

Changed files
+61 -16
nixos
modules
services
web-servers
tests
web-servers
h2o
+19 -12
nixos/modules/services/web-servers/h2o/default.nix
···
headerSet ++ [ hsts ];
}
);
-
in
-
value.settings
-
// headerRecAttrs
-
// {
+
listen =
let
identity =
···
key-file = "${certs.${names.cert}.directory}/key.pem";
certificate-file = "${certs.${names.cert}.directory}/fullchain.pem";
};
+
+
baseListen =
+
{
+
port = port.TLS;
+
ssl = (lib.recursiveUpdate tlsRecAttrs value.tls.extraSettings) // {
+
inherit identity;
+
};
+
}
+
// lib.optionalAttrs (value.host != null) {
+
host = value.host;
+
};
+
+
# QUIC, if used, will duplicate the TLS over TCP directive, but
+
# append some extra QUIC-related settings
+
quicListen = lib.optional (value.tls.quic != null) (baseListen // { inherit (value.tls) quic; });
in
{
-
port = port.TLS;
-
ssl = (lib.recursiveUpdate tlsRecAttrs value.tls.extraSettings) // {
-
inherit identity;
-
};
-
}
-
// lib.optionalAttrs (value.host != null) {
-
host = value.host;
+
listen = [ baseListen ] ++ quicListen;
};
-
};
+
in
+
value.settings // headerRecAttrs // listen;
};
in
# With a high likelihood of HTTP & ACME challenges being on the same port,
+19
nixos/modules/services/web-servers/h2o/vhost-options.nix
···
'';
};
recommendations = tlsRecommendationsOption;
+
quic = mkOption {
+
type = types.nullOr types.attrs;
+
default = null;
+
description = ''
+
Enables HTTP/3 over QUIC on the UDP port for TLS. The attrset
+
provides fine-turning for QUIC behavior, but can be empty. See
+
<https://h2o.examp1e.net/configure/http3_directives.html#quic-attributes>.
+
'';
+
example =
+
literalExpression
+
# nix
+
''
+
{
+
amp-limit = 2;
+
handshake-timeout-rtt-multiplier = 300;
+
retry = "ON";
+
}
+
'';
+
};
extraSettings = mkOption {
type = types.attrs;
default = { };
+23 -4
nixos/tests/web-servers/h2o/basic.nix
···
server =
{ pkgs, ... }:
{
+
environment.systemPackages = [
+
pkgs.curlHTTP3
+
];
+
services.h2o = {
enable = true;
defaultHTTPListenPort = port.HTTP;
···
"${domain.TLS}" = {
tls = {
policy = "force";
+
quic = {
+
retry = "ON";
+
};
identity = [
{
key-file = ../../common/acme/server/acme.test.key.pem;
···
];
networking = {
-
firewall.allowedTCPPorts = with port; [
-
HTTP
-
TLS
-
];
+
firewall = {
+
allowedTCPPorts = with port; [
+
HTTP
+
TLS
+
];
+
allowedUDPPorts = with port; [
+
TLS
+
];
+
};
extraHosts = ''
127.0.0.1 ${domain.HTTP}
127.0.0.1 ${domain.TLS}
···
assert "content-type: text/x-rst" in tls_hello_world_head
assert "${sawatdi_chao_lok}" in server.succeed("curl -v --http2 --tlsv1.3 --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'")
+
+
quic_hello_world_head = server.succeed("curl -v --head --compressed --http3-only --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'").lower()
+
assert "http/3 200" in quic_hello_world_head
+
assert "server: h2o" in quic_hello_world_head
+
assert "content-type: text/x-rst" in quic_hello_world_head
+
+
assert "${sawatdi_chao_lok}" in server.succeed("curl -v --http3-only --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'")
assert "redirected" in server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'").lower()