nixos/h2o: enable HTTP/3 via QUIC

This commit is contained in:
โทสฺตัล
2025-03-27 18:57:52 +07:00
parent 301581e073
commit 7554581474
3 changed files with 61 additions and 16 deletions

View File

@@ -221,10 +221,7 @@ let
headerSet ++ [ hsts ];
}
);
in
value.settings
// headerRecAttrs
// {
listen =
let
identity =
@@ -233,17 +230,27 @@ let
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,

View File

@@ -152,6 +152,25 @@ in
'';
};
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 = { };

View File

@@ -43,6 +43,10 @@ in
server =
{ pkgs, ... }:
{
environment.systemPackages = [
pkgs.curlHTTP3
];
services.h2o = {
enable = true;
defaultHTTPListenPort = port.HTTP;
@@ -60,6 +64,9 @@ in
"${domain.TLS}" = {
tls = {
policy = "force";
quic = {
retry = "ON";
};
identity = [
{
key-file = ../../common/acme/server/acme.test.key.pem;
@@ -99,10 +106,15 @@ in
];
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}
@@ -130,6 +142,13 @@ in
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()
server.fail("curl --location --max-redirs 0 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'")