nixos/h2o: enable HTTP/3 via QUIC

+61 -16
+19 -12
nixos/modules/services/web-servers/h2o/default.nix
··· 221 221 headerSet ++ [ hsts ]; 222 222 } 223 223 ); 224 - in 225 - value.settings 226 - // headerRecAttrs 227 - // { 224 + 228 225 listen = 229 226 let 230 227 identity = ··· 233 230 key-file = "${certs.${names.cert}.directory}/key.pem"; 234 231 certificate-file = "${certs.${names.cert}.directory}/fullchain.pem"; 235 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; }); 236 248 in 237 249 { 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; 245 251 }; 246 - }; 252 + in 253 + value.settings // headerRecAttrs // listen; 247 254 }; 248 255 in 249 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 152 ''; 153 153 }; 154 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 + }; 155 174 extraSettings = mkOption { 156 175 type = types.attrs; 157 176 default = { };
+23 -4
nixos/tests/web-servers/h2o/basic.nix
··· 43 43 server = 44 44 { pkgs, ... }: 45 45 { 46 + environment.systemPackages = [ 47 + pkgs.curlHTTP3 48 + ]; 49 + 46 50 services.h2o = { 47 51 enable = true; 48 52 defaultHTTPListenPort = port.HTTP; ··· 60 64 "${domain.TLS}" = { 61 65 tls = { 62 66 policy = "force"; 67 + quic = { 68 + retry = "ON"; 69 + }; 63 70 identity = [ 64 71 { 65 72 key-file = ../../common/acme/server/acme.test.key.pem; ··· 99 106 ]; 100 107 101 108 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 + }; 106 118 extraHosts = '' 107 119 127.0.0.1 ${domain.HTTP} 108 120 127.0.0.1 ${domain.TLS} ··· 129 141 assert "content-type: text/x-rst" in tls_hello_world_head 130 142 131 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'") 132 151 133 152 assert "redirected" in server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${portStrHTTP}/hello_world.rst'").lower() 134 153