I just migrated this webserver to Caddy 2 and with it, enabled HTTP/3 support. This post will give a short explanation how you can do that.
Run Caddy 2
The HTTP/3 feature is only available in caddy 2, make sure you run at least version 2 or higher.
This is bad:
caddy --version
Caddy v1.0.3 (h1:i9gRhBgvc5ifchwWtSe7pDpsdS9+Q0Rw9oYQmYUTw1w=)
This is good:
$ caddy version
v2.0.0-rc.2 h1:7NOaxYrsnQ5D3rcLGn2UnLZHLfBpgrfM/JNTLhjCJ1c=
(Note how the syntax changed from --version
to version
).
Enable HTTP/3
In your Caddyfile
, at the very top, enable the HTTP/3 feature.
{
experimental_http3
}
ma.ttias.be {
root * /var/www/html/ma.ttias.be/public
file_server
encode zstd gzip
[...]
}
The critical part is experimental_http3
.
TCP and UDP
One major change is that HTTP/3 operates on the UDP protocol instead of TCP. Most webservers will only bind on port :80 and :443 on TCP, as they don’t need to do any UDP traffic.
By default, Caddy will also only listen on TCP:
tcp6 0 0 :::80 :::* LISTEN 27373/caddy
tcp6 0 0 :::443 :::* LISTEN 27373/caddy
If you enable the experimental_http3
option, it’ll listen on UDP as well.
tcp6 0 0 :::80 :::* LISTEN 27422/caddy
tcp6 0 0 :::443 :::* LISTEN 27422/caddy
udp6 0 0 :::443 :::* 27422/caddy
(Note: if you’re used to running netstat | grep " LISTEN "
, be aware that the UDP protocol doesn’t have a LISTEN state attached to it and won’t return any results).
If you see a UDP listener, you’re ready to receive connections.
Allow UDP traffic
Since the shift from TCP to UDP might catch some firewall vendors by surprise, make sure you’re allowing 443/udp incoming to your server.
443/tcp is probably already allowed (or you wouldn’t be serving HTTPS sites today).
Test HTTP/3 connections
This part is a bit more tricky, since it’s all very experimental and none of the client tooling supports HTTP/3 by default.
Via curl
Curl has, since its recent versions, introduced a --http3
flag you can use to force HTTP/3 connections.
$ curl -I --http3 https://ma.ttias.be
HTTP/3 200
alt-svc: h3-27=":443"; ma=2592000
server: Caddy
...
You’ll need a modern version though, and most distributions don’t ship with it by default. The above was done with a custom-compiled version of curl
to test HTTP/3.
$ curl --version
curl 7.70.0-DEV
Via Chrome Canary
Chrome Canary is a nightly build of Chrome, with some more experimental features in it.
To test it out, make sure you’re running the latest version and start Chrome Canary with the --enable-quic
and --quic-version=h3-27
flag. You will need to start Chrome Canary via the CLI.
(Note: the version of QUIC should match the one that is advertised in the alt-svc
header.)
If you are on a Mac, you can start Chrome Canary like this:
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary \
--enable-quic \
--quic-version=h3-27
The first page load will show HTTP/2. From then on, the browser has received the alt-svc
header to indicate there is HTTP/3 support and will retry the next request over UDP & HTTP/3.
Because HTTP/3 is still evolving, Chrome shows the exact revision of the HTTP/3 protocol being used.
Via Firefox Nightly
Just like Chrome, Firefox has an experimental build called Firefox Nightly.
First, enable HTTP/3. Navigate to about:config
and find the option network.http.http3.enabled
. Doubleclick it to toggle it from disabled to enabled.
Refresh your site and it should show HTTP/3 in the inspector. Make sure the Protocol column is shown.
Conclusion
HTTP/3 is still very experimental. Server-side support is slowly coming, but client-side support is disabled by default everywhere.
We’re still in the trial & error phase, I’m curious to see when the the first browsers will ship with HTTP/3 enabled.
It’s a chicken and egg situation right now: there’s little incentive for servers to implement it, as no clients support it. And why should clients push forward, if no servers provide the support?