Skip to content

Commit 5a2d8c3

Browse files
authored
nixos/h2o: enable HTTP/3 via QUIC (#388953)
2 parents 78f33e1 + 7554581 commit 5a2d8c3

File tree

4 files changed

+68
-30
lines changed

4 files changed

+68
-30
lines changed

nixos/modules/services/web-servers/h2o/default.nix

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,7 @@ let
221221
headerSet ++ [ hsts ];
222222
}
223223
);
224-
in
225-
value.settings
226-
// headerRecAttrs
227-
// {
224+
228225
listen =
229226
let
230227
identity =
@@ -233,17 +230,27 @@ let
233230
key-file = "${certs.${names.cert}.directory}/key.pem";
234231
certificate-file = "${certs.${names.cert}.directory}/fullchain.pem";
235232
};
233+
234+
baseListen =
235+
{
236+
port = port.TLS;
237+
ssl = (lib.recursiveUpdate tlsRecAttrs value.tls.extraSettings) // {
238+
inherit identity;
239+
};
240+
}
241+
// lib.optionalAttrs (value.host != null) {
242+
host = value.host;
243+
};
244+
245+
# QUIC, if used, will duplicate the TLS over TCP directive, but
246+
# append some extra QUIC-related settings
247+
quicListen = lib.optional (value.tls.quic != null) (baseListen // { inherit (value.tls) quic; });
236248
in
237249
{
238-
port = port.TLS;
239-
ssl = (lib.recursiveUpdate tlsRecAttrs value.tls.extraSettings) // {
240-
inherit identity;
241-
};
242-
}
243-
// lib.optionalAttrs (value.host != null) {
244-
host = value.host;
250+
listen = [ baseListen ] ++ quicListen;
245251
};
246-
};
252+
in
253+
value.settings // headerRecAttrs // listen;
247254
};
248255
in
249256
# With a high likelihood of HTTP & ACME challenges being on the same port,
@@ -351,7 +358,7 @@ in
351358
"hydra.example.com" = {
352359
tls = {
353360
policy = "force";
354-
indentity = [
361+
identity = [
355362
{
356363
key-file = "/path/to/key";
357364
certificate-file = "/path/to/cert";

nixos/modules/services/web-servers/h2o/vhost-options.nix

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,25 @@ in
152152
'';
153153
};
154154
recommendations = tlsRecommendationsOption;
155+
quic = mkOption {
156+
type = types.nullOr types.attrs;
157+
default = null;
158+
description = ''
159+
Enables HTTP/3 over QUIC on the UDP port for TLS. The attrset
160+
provides fine-turning for QUIC behavior, but can be empty. See
161+
<https://h2o.examp1e.net/configure/http3_directives.html#quic-attributes>.
162+
'';
163+
example =
164+
literalExpression
165+
# nix
166+
''
167+
{
168+
amp-limit = 2;
169+
handshake-timeout-rtt-multiplier = 300;
170+
retry = "ON";
171+
}
172+
'';
173+
};
155174
extraSettings = mkOption {
156175
type = types.attrs;
157176
default = { };

nixos/tests/web-servers/h2o/basic.nix

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ in
4343
server =
4444
{ pkgs, ... }:
4545
{
46+
environment.systemPackages = [
47+
pkgs.curlHTTP3
48+
];
49+
4650
services.h2o = {
4751
enable = true;
4852
defaultHTTPListenPort = port.HTTP;
@@ -60,6 +64,9 @@ in
6064
"${domain.TLS}" = {
6165
tls = {
6266
policy = "force";
67+
quic = {
68+
retry = "ON";
69+
};
6370
identity = [
6471
{
6572
key-file = ../../common/acme/server/acme.test.key.pem;
@@ -99,18 +106,22 @@ in
99106
];
100107

101108
networking = {
102-
firewall.allowedTCPPorts = with port; [
103-
HTTP
104-
TLS
105-
];
109+
firewall = {
110+
allowedTCPPorts = with port; [
111+
HTTP
112+
TLS
113+
];
114+
allowedUDPPorts = with port; [
115+
TLS
116+
];
117+
};
106118
extraHosts = ''
107119
127.0.0.1 ${domain.HTTP}
108120
127.0.0.1 ${domain.TLS}
109121
'';
110122
};
111123
};
112124
};
113-
114125
testScript =
115126
let
116127
portStrHTTP = builtins.toString port.HTTP;
@@ -122,23 +133,26 @@ in
122133
server.wait_for_open_port(${portStrHTTP})
123134
server.wait_for_open_port(${portStrTLS})
124135
125-
http_hello_world_body = server.succeed("curl --fail-with-body 'http://${domain.HTTP}:${portStrHTTP}/hello_world.txt'")
126-
assert "${sawatdi_chao_lok}" in http_hello_world_body
136+
assert "${sawatdi_chao_lok}" in server.succeed("curl --fail-with-body 'http://${domain.HTTP}:${portStrHTTP}/hello_world.txt'")
127137
128138
tls_hello_world_head = server.succeed("curl -v --head --compressed --http2 --tlsv1.3 --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'").lower()
129139
assert "http/2 200" in tls_hello_world_head
130140
assert "server: h2o" in tls_hello_world_head
131141
assert "content-type: text/x-rst" in tls_hello_world_head
132142
133-
tls_hello_world_body = server.succeed("curl -v --http2 --tlsv1.3 --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'")
134-
assert "${sawatdi_chao_lok}" in tls_hello_world_body
143+
assert "${sawatdi_chao_lok}" in server.succeed("curl -v --http2 --tlsv1.3 --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'")
144+
145+
quic_hello_world_head = server.succeed("curl -v --head --compressed --http3-only --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'").lower()
146+
assert "http/3 200" in quic_hello_world_head
147+
assert "server: h2o" in quic_hello_world_head
148+
assert "content-type: text/x-rst" in quic_hello_world_head
149+
150+
assert "${sawatdi_chao_lok}" in server.succeed("curl -v --http3-only --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'")
135151
136-
tls_hello_world_head_redirected = server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${builtins.toString port.HTTP}/hello_world.rst'").lower()
137-
assert "redirected" in tls_hello_world_head_redirected
152+
assert "redirected" in server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'").lower()
138153
139154
server.fail("curl --location --max-redirs 0 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'")
140155
141-
tls_hello_world_body_redirected = server.succeed("curl -v --location --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'")
142-
assert "${sawatdi_chao_lok}" in tls_hello_world_body_redirected
156+
assert "${sawatdi_chao_lok}" in server.succeed("curl -v --location --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'")
143157
'';
144158
}

nixos/tests/web-servers/h2o/mruby.nix

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,8 @@ in
5858
server.wait_for_unit("h2o.service")
5959
server.wait_for_open_port(${portStr})
6060
61-
hello_world = server.succeed("curl --fail-with-body http://${domain}:${portStr}/hello_world")
62-
assert "${sawatdi_chao_lok}" in hello_world
61+
assert "${sawatdi_chao_lok}" in server.succeed("curl --fail-with-body http://${domain}:${portStr}/hello_world")
6362
64-
file_handler = server.succeed("curl --fail-with-body http://${domain}:${portStr}/file_handler")
65-
assert "FILE_HANDLER" in file_handler
63+
assert "FILE_HANDLER" in server.succeed("curl --fail-with-body http://${domain}:${portStr}/file_handler")
6664
'';
6765
}

0 commit comments

Comments
 (0)