Repository: caddyserver/caddy (language: go)

Issue:
caddy 2.5.1 + experimental_http3 + fastcgi reverse_proxy always returns 500
```
caddy version
v2.5.1 h1:bAWwslD1jNeCzDa+jDCNwb8M3UJ2tPa8UZFFzPVmGKs=
```

Running caddy on a 64-bit install of raspberry pi os lite.

Have a small go app acting as a fastcgi server listening on a unix socket.  This app is using the standard `"net/http/fcgi"` package in go 1.18.2: https://github.com/aaronriekenberg/go-fastcgi

caddy is acting as a file server and reverse proxy to the go fastcgi app.

Things work perfectly with the default HTTP/2 in caddy.

But as soon as I enable `experimental_http3` in my Caddyfile I observe:
1. All requests going over the fastcgi reverse_proxy return 500
2. Putting logging into my go-fastcgi server app - I see the fastcgi handler is never invoked when caddy is using `experimental_http3`
3. Turned on debug logging in caddy and have logs as below.
4. All requests that do not use fastcgi reverse_proxy (e.g. file_server) work normally with `experimental_http3` and I see in chrome dev tools the requests are using http3.  So the issue seems isolated to `experimental_http3` + fastcgi reverse_proxy.

My Caddyfile:

```
{
        email aaron.riekenberg@gmail.com
        debug
        servers :443 {
                protocol {
                        experimental_http3
                }
        }
}

www.aaronr.digital, aaronr.digital {
        log {
                output file /var/log/caddy/access.log {
                        roll_size 10mb
                        roll_keep 5
                }
        }

        root * /var/www/html/aaronr.digital

        header {
                Cache-Control "no-cache"
                Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
        }

        handle /cgi-bin/* {
                reverse_proxy unix//var/www/run/go-fastcgi/socket {
                        transport fastcgi
                }
        }

        handle {
                header Cache-Control "public, max-age=150"

                file_server {
                        hide /var/www/html/aaronr.digital/.git/*
                        precompressed br
                }
        }

        handle_errors {
                rewrite * /error.html
                templates
                file_server
                header Cache-Control "no-cache"
        }
}
```

Debug errors in caddy log when making a request using http3:

```
May 29 10:29:16 raspberrypi caddy[1633]: {"level":"debug","ts":1653838156.6797538,"logger":"http.handlers.reverse_proxy","msg":"selected upstream","dial":"/var/www/run/go-fastcgi/socket","total_upstreams":1}
May 29 10:29:16 raspberrypi caddy[1633]: {"level":"debug","ts":1653838156.6806445,"logger":"http.reverse_proxy.transport.fastcgi","msg":"roundtrip","request":{"remote_ip":"2600:6c46:7c00:e89f:e5a0:f1cf:54d:2e04","remote_port":"55767","proto":"HTTP/3","method":"GET","host":"aaronr.digital","uri":"/cgi-bin/debug/request_info","headers":{"Sec-Ch-Ua-Mobile":["?0"],"Accept-Language":["en-US,en;q=0.9"],"X-Forwarded-For":["2600:6c46:7c00:e89f:e5a0:f1cf:54d:2e04"],"Sec-Ch-Ua":["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\""],"Axios-Version":["0.27.2"],"Sec-Ch-Ua-Platform":["\"macOS\""],"Sec-Fetch-Dest":["empty"],"X-Forwarded-Host":["aaronr.digital"],"Sec-Fetch-Site":["same-origin"],"Sec-Fetch-Mode":["cors"],"Accept-Encoding":["gzip, deflate, br"],"Accept":["application/json, text/plain, */*"],"X-Forwarded-Proto":["https"],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36"],"Referer":["https://aaronr.digital/debug/request_info.html"]},"tls":{"resumed":false,"version":0,"cipher_suite":0,"proto":"","server_name":""}},"dial":"/var/www/run/go-fastcgi/socket","env":{"HTTP_ACCEPT":"application/json, text/plain, */*","HTTP_X_FORWARDED_PROTO":"https","HTTP_SEC_FETCH_SITE":"same-origin","HTTP_SEC_CH_UA_MOBILE":"?0","CONTENT_TYPE":"","SERVER_PROTOCOL":"HTTP/3","SERVER_SOFTWARE":"Caddy/v2.5.1","DOCUMENT_ROOT":"/var/www/html/aaronr.digital","HTTP_X_FORWARDED_FOR":"2600:6c46:7c00:e89f:e5a0:f1cf:54d:2e04","HTTP_SEC_CH_UA_PLATFORM":"\"macOS\"","QUERY_STRING":"","SCRIPT_NAME":"","HTTP_REFERER":"https://aaronr.digital/debug/request_info.html","HTTP_HOST":"aaronr.digital","PATH_TRANSLATED":"/var/www/html/aaronr.digital/cgi-bin/debug/request_info","SERVER_PORT":"443","HTTP_ACCEPT_LANGUAGE":"en-US,en;q=0.9","GATEWAY_INTERFACE":"CGI/1.1","REMOTE_USER":"","REQUEST_SCHEME":"https","DOCUMENT_URI":"","HTTP_X_FORWARDED_HOST":"aaronr.digital","SCRIPT_FILENAME":"/var/www/html/aaronr.digital","HTTP_AXIOS_VERSION":"0.27.2","CONTENT_LENGTH":"","PATH_INFO":"/cgi-bin/debug/request_info","REMOTE_HOST":"2600:6c46:7c00:e89f:e5a0:f1cf:54d:2e04","REQUEST_METHOD":"GET","REMOTE_ADDR":"2600:6c46:7c00:e89f:e5a0:f1cf:54d:2e04","SERVER_NAME":"aaronr.digital","HTTP_SEC_CH_UA":"\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\"","HTTP_SEC_FETCH_DEST":"empty","AUTH_TYPE":"","REMOTE_PORT":"55767","HTTPS":"on","HTTP_SEC_FETCH_MODE":"cors","REMOTE_IDENT":"","REQUEST_URI":"/cgi-bin/debug/request_info","HTTP_ACCEPT_ENCODING":"gzip, deflate, br","HTTP_USER_AGENT":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36"}}
May 29 10:29:16 raspberrypi caddy[1633]: {"level":"debug","ts":1653838156.6995711,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"unix//var/www/run/go-fastcgi/socket","duration":0.01931079,"request":{"remote_ip":"2600:6c46:7c00:e89f:e5a0:f1cf:54d:2e04","remote_port":"55767","proto":"HTTP/3","method":"GET","host":"aaronr.digital","uri":"/cgi-bin/debug/request_info","headers":{"Referer":["https://aaronr.digital/debug/request_info.html"],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36"],"Accept-Language":["en-US,en;q=0.9"],"X-Forwarded-For":["2600:6c46:7c00:e89f:e5a0:f1cf:54d:2e04"],"Sec-Ch-Ua-Mobile":["?0"],"Axios-Version":["0.27.2"],"Sec-Ch-Ua-Platform":["\"macOS\""],"Sec-Fetch-Dest":["empty"],"X-Forwarded-Host":["aaronr.digital"],"Sec-Ch-Ua":["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\""],"Sec-Fetch-Mode":["cors"],"Accept-Encoding":["gzip, deflate, br"],"Accept":["application/json, text/plain, */*"],"X-Forwarded-Proto":["https"],"Sec-Fetch-Site":["same-origin"]},"tls":{"resumed":false,"version":0,"cipher_suite":0,"proto":"","server_name":""}},"headers":{"Status":["500 Internal Server Error"],"Content-Type":["text/plain; charset=utf-8"],"Date":["Sun, 29 May 2022 15:29:16 GMT"]},"status":500}
```


Discussion / hints:
Are you able to use wireshark or similar to watch the traffic? I think the 500 status message must be coming from the upstream, it might not be happy with something in the request before it reaches your handler.
@francislavoie thanks will try this and post the results. 
@francislavoie - 

I was not able to find a way to sniff packets for the unix socket.  So I changed the go-fastcgi app to listen on tcp port 9000, and I changed my Caddyfile to:

```
       handle /cgi-bin/* {
                reverse_proxy 127.0.0.1:9000 {
                        transport fastcgi
                }
        }
```

With this I was able to recreate the http3 500 errors, and http2 worked as expected.

Here is some data from Wireshark showing responses from go-fastcgi to caddy when using http/3:

<img width="1059" alt="image" src="https://user-images.githubusercontent.com/991901/170894632-50edee08-9c3e-475a-a26b-aed596d4a094.png">

<img width="991" alt="image" src="https://user-images.githubusercontent.com/991901/170894646-d01ac276-8ee6-4ce4-91da-3c50e7104560.png">

So it looks like my go-fastcgi app is hitting this: https://github.com/golang/go/blob/master/src/net/http/cgi/child.go#L62

`cgi: invalid SERVER_PROTOCOL version`

From caddy debug logs - I have seen in outgoing fastcgi requests when using http3 in caddy:

```
"SERVER_PROTOCOL":"HTTP/3"
```

and when using http2 in caddy I see this in outgoing fastcgi requests:

```
"SERVER_PROTOCOL":"HTTP/2.0"
```

So finally I think the issue is go's `http. ParseHTTPVersion` here does not accept `HTTP/3` but does accept `HTTP/2.0`: https://github.com/golang/go/blob/master/src/net/http/request.go#L787-L790

See this go playground for a small demo: https://go.dev/play/p/HgK2fi1r8Bb

I *think* this is probably a bug in caddy in that `SERVER_PROTOCOL` should be `HTTP/3.0` when using reverse_proxy + fastcgi with incoming http3 requests?


Further observations:

1.  I think caddy is setting `SERVER_PROTOCOL` to `r.Proto` here: https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go#L286

    Then after this configured `env` key/values from the fastcgi transport are set: https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go#L335-L338

    So I tried changing my Caddyfile to set `SERVER_PROTOCOL` to `HTTP/3.0` in the fastcgi transport env:

    ```
        handle /cgi-bin/* {
                reverse_proxy unix//var/www/run/go-fastcgi/socket {
                        transport fastcgi {
                                env SERVER_PROTOCOL HTTP/3.0
                        }
                }
        }
    ```

    This worked completely end-to-end with an HTTP/3 request making it all the way to my go-fastcgi app 😃 

2. I suspect the `HTTP/3` value for `r.Proto` may be coming from quic-go here: https://github.com/lucas-clemente/quic-go/blob/master/http3/request.go#L77

    But I may be missing something on how `HTTP/3` is being used in quic-go and caddy.  Does this make sense?  Thanks!

Interesting. Thanks for investigating!

FYI @marten-seemann, I think quic-go should report `HTTP/3.0` instead of `HTTP/3`, supposedly the minor version is required
Thanks for the deep investigation! Sounds like a likely easy fix.
What makes you think that it should be HTTP/3.0? The name of the protocol is HTTP/3 (compare to HTTP/2, which specifies HTTP/2.0 preface here: https://datatracker.ietf.org/doc/html/rfc7540#section-3.5).
@marten-seemann -

My use case is:
1. I have caddy running as a fastcgi reverse proxy
2. A small go app is my fastcgi server (https://github.com/aaronriekenberg/go-fastcgi).  This is using the standard `"net/http/fcgi"` package in go 1.18.2
3. caddy is connecting to go-fastcgi app via a unix socket

With out-of-the-box HTTP/2 in caddy everything works as expected.

I tried turning on `experimental_http3` in caddy and noticed all fastcgi requests to go-fastcgi were returning 500 in caddy.  With http3 enabled in caddy my `http.Handler` in go-fastcgi is never called.

After some debugging above - I am finding:

1. caddy is setting the fastcgi `SERVER_PROTOCOL` to `r.Proto` here: https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go#L286
    a. When using HTTP/2 `r.Proto` is `HTTP/2.0`
    b. When using HTTP/3 `r.Proto` is `HTTP/3`  It looks like this comes from quic-go here: https://github.com/lucas-clemente/quic-go/blob/master/http3/request.go#L77

2. From some packet sniffing between caddy and go-fastcgi - the error returned with from go-fastcgi when using http3 is `cgi: invalid SERVER_PROTOCOL version` here: https://github.com/golang/go/blob/master/src/net/http/cgi/child.go#L62

    This happens on the way into go-fastcgi as part of the `net/http/fcgi` package parsing the request, before any user handler is invoked.

3. Looks like the reason for this error in `net/http/fcgi` is the SERVER_PROTOCOL value is passed to `http.ParseHTTPVersion`: https://github.com/golang/go/blob/master/src/net/http/cgi/child.go#L58-L60

    `http.ParseHTTPVersion` seems to require a very specific `HTTP/X.Y` string format - `HTTP/3` is not considered valid.  See this go playground: https://go.dev/play/p/9t13-xYkyxl

   The comments in `http.ParseHTTPVersion` also state this requirement: https://github.com/golang/go/blob/master/src/net/http/request.go#L787-L790


A couple of thoughts on how to fix this:
1. quic-go could set the request protocol field to `HTTP/3.0` to make `http.ParseHTTPVersion` work if the request is sent to a fastcgi server using go's `net/http/fcgi`
2. If `HTTP/3` is correct perhaps go should update `http.ParseHTTPVersion` to accept this ?  


Thanks!
The `:protocol` pseudo-header is only sent when using Extended CONNECT: https://github.com/lucas-clemente/quic-go/blob/b5ef99a32c250fc63f89cc686c13a008c5419d01/http3/request_writer.go#L178-L180.

HTTP/3 doesn't specify a serialization of the HTTP version, as far as I can see: https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-34#section-4.1.1.1. So it seems like the value we set on the `http.Request` is entire implementation- / Go-specific.

@aaronriekenberg Do you agree with that reading? If so, do you want to send a PR in quic-go?

Created a PR for quic-go: https://github.com/lucas-clemente/quic-go/pull/3439

Thank you!
facing the same problem with **reverse_proxy**, here's the clue

v2.5.1 h1:bAWwslD1jNeCzDa+jDCNwb8M3UJ2tPa8UZFFzPVmGKs=


```
	route /hello/* {
		header X-Real-IP {http.request.remote}
		reverse_proxy http://127.0.01:3000
	}
```

(http://127.0.01:3000 is also serving with caddy2 as **encode zstd gzip**.)

when got 500 failed, it reports following error
```
{
  "error": "{id=yeq4edcjs} fileserver.(*FileServer).notFound (staticfiles.go:511): HTTP 404",
  "first_error": {
    "msg": "template: /hello/:3: unrecognized character in action: U+FFFD '�'",
    "status": 500,
    "err_id": "swt6pk6tb",
    "err_trace": "templates.(*Templates).executeTemplate (templates.go:372)"
  }
}
```

-------
updated: 
`curl -v` works fine. the issue pattern is `encode zstd gzip → reverse_proxy → templates`
remove **encode zstd gzip** from target server or the **templates** from current server deliminates the 500 error

@mindon I'm pretty sure that's not the same problem as was described in this issue either. This issue was specific to HTTP/3, and did not involve `templates`.

That said, we can close this soon, once we bump the quic-go dependency to v0.28.0 (FYI @mholt if you want to do that just before our next release https://github.com/lucas-clemente/quic-go/releases/tag/v0.28.0)

Fix patch:
diff --git a/go.mod b/go.mod
index 077e83437ad..814d13591f4 100644
--- a/go.mod
+++ b/go.mod
@@ -14,7 +14,7 @@ require (
 	github.com/google/uuid v1.3.0
 	github.com/klauspost/compress v1.15.6
 	github.com/klauspost/cpuid/v2 v2.0.13
-	github.com/lucas-clemente/quic-go v0.27.2
+	github.com/lucas-clemente/quic-go v0.28.0
 	github.com/mholt/acmez v1.0.2
 	github.com/prometheus/client_golang v1.12.1
 	github.com/smallstep/certificates v0.19.0
@@ -30,7 +30,7 @@ require (
 	go.opentelemetry.io/otel/sdk v1.4.0
 	go.uber.org/zap v1.21.0
 	golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2
-	golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
+	golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
 	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
 	google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21
 	google.golang.org/protobuf v1.28.0
@@ -83,6 +83,7 @@ require (
 	github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
 	github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
 	github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
+	github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 // indirect
 	github.com/mattn/go-colorable v0.1.8 // indirect
 	github.com/mattn/go-isatty v0.0.13 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
@@ -121,7 +122,7 @@ require (
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
 	golang.org/x/mod v0.4.2 // indirect
-	golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
+	golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
 	golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
 	golang.org/x/tools v0.1.7 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
diff --git a/go.sum b/go.sum
index 56ae7cab2ab..086df08c150 100644
--- a/go.sum
+++ b/go.sum
@@ -722,8 +722,8 @@ github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
 github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
-github.com/lucas-clemente/quic-go v0.27.2 h1:zsMwwniyybb8B/UDNXRSYee7WpQJVOcjQEGgpw2ikXs=
-github.com/lucas-clemente/quic-go v0.27.2/go.mod h1:vXgO/11FBSKM+js1NxoaQ/bPtVFYfB7uxhfHXyMhl1A=
+github.com/lucas-clemente/quic-go v0.28.0 h1:9eXVRgIkMQQyiyorz/dAaOYIx3TFzXsIFkNFz4cxuJM=
+github.com/lucas-clemente/quic-go v0.28.0/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
 github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
@@ -741,6 +741,8 @@ github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR
 github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
 github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
 github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
+github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 h1:7m/WlWcSROrcK5NxuXaxYD32BZqe/LEEnBrWcH/cOqQ=
+github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -1365,8 +1367,9 @@ golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
+golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1508,8 +1511,9 @@ golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
 golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
diff --git a/modules/caddyhttp/app.go b/modules/caddyhttp/app.go
index d886b888ac9..4a8a3755f24 100644
--- a/modules/caddyhttp/app.go
+++ b/modules/caddyhttp/app.go
@@ -357,12 +357,10 @@ func (app *App) Start() error {
 							return fmt.Errorf("getting HTTP/3 QUIC listener: %v", err)
 						}
 						h3srv := &http3.Server{
-							Server: &http.Server{
-								Addr:      hostport,
-								Handler:   srv,
-								TLSConfig: tlsCfg,
-								ErrorLog:  serverLogger,
-							},
+							Addr:           hostport,
+							Handler:        srv,
+							TLSConfig:      tlsCfg,
+							MaxHeaderBytes: srv.MaxHeaderBytes,
 						}
 						//nolint:errcheck
 						go h3srv.ServeListener(h3ln)


Test patch: