nixos/h2o: enable HTTP/3 via QUIC

+61 -16
+19 -12
nixos/modules/services/web-servers/h2o/default.nix
··· 221 headerSet ++ [ hsts ]; 222 } 223 ); 224 - in 225 - value.settings 226 - // headerRecAttrs 227 - // { 228 listen = 229 let 230 identity = ··· 233 key-file = "${certs.${names.cert}.directory}/key.pem"; 234 certificate-file = "${certs.${names.cert}.directory}/fullchain.pem"; 235 }; 236 in 237 { 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; 245 }; 246 - }; 247 }; 248 in 249 # With a high likelihood of HTTP & ACME challenges being on the same port,
··· 221 headerSet ++ [ hsts ]; 222 } 223 ); 224 + 225 listen = 226 let 227 identity = ··· 230 key-file = "${certs.${names.cert}.directory}/key.pem"; 231 certificate-file = "${certs.${names.cert}.directory}/fullchain.pem"; 232 }; 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; }); 248 in 249 { 250 + listen = [ baseListen ] ++ quicListen; 251 }; 252 + in 253 + value.settings // headerRecAttrs // listen; 254 }; 255 in 256 # With a high likelihood of HTTP & ACME challenges being on the same port,
+19
nixos/modules/services/web-servers/h2o/vhost-options.nix
··· 152 ''; 153 }; 154 recommendations = tlsRecommendationsOption; 155 extraSettings = mkOption { 156 type = types.attrs; 157 default = { };
··· 152 ''; 153 }; 154 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 + }; 174 extraSettings = mkOption { 175 type = types.attrs; 176 default = { };
+23 -4
nixos/tests/web-servers/h2o/basic.nix
··· 43 server = 44 { pkgs, ... }: 45 { 46 services.h2o = { 47 enable = true; 48 defaultHTTPListenPort = port.HTTP; ··· 60 "${domain.TLS}" = { 61 tls = { 62 policy = "force"; 63 identity = [ 64 { 65 key-file = ../../common/acme/server/acme.test.key.pem; ··· 99 ]; 100 101 networking = { 102 - firewall.allowedTCPPorts = with port; [ 103 - HTTP 104 - TLS 105 - ]; 106 extraHosts = '' 107 127.0.0.1 ${domain.HTTP} 108 127.0.0.1 ${domain.TLS} ··· 129 assert "content-type: text/x-rst" in tls_hello_world_head 130 131 assert "${sawatdi_chao_lok}" in server.succeed("curl -v --http2 --tlsv1.3 --compressed --fail-with-body 'https://${domain.TLS}:${portStrTLS}/hello_world.rst'") 132 133 assert "redirected" in server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'").lower() 134
··· 43 server = 44 { pkgs, ... }: 45 { 46 + environment.systemPackages = [ 47 + pkgs.curlHTTP3 48 + ]; 49 + 50 services.h2o = { 51 enable = true; 52 defaultHTTPListenPort = port.HTTP; ··· 64 "${domain.TLS}" = { 65 tls = { 66 policy = "force"; 67 + quic = { 68 + retry = "ON"; 69 + }; 70 identity = [ 71 { 72 key-file = ../../common/acme/server/acme.test.key.pem; ··· 106 ]; 107 108 networking = { 109 + firewall = { 110 + allowedTCPPorts = with port; [ 111 + HTTP 112 + TLS 113 + ]; 114 + allowedUDPPorts = with port; [ 115 + TLS 116 + ]; 117 + }; 118 extraHosts = '' 119 127.0.0.1 ${domain.HTTP} 120 127.0.0.1 ${domain.TLS} ··· 141 assert "content-type: text/x-rst" in tls_hello_world_head 142 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'") 151 152 assert "redirected" in server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'").lower() 153