How to run HTTP/3 with Caddy 2

Tired of the privacy invasion of the Chrome webbrowser? Worried about the risk of seeing ads everywhere? Give the Brave Browser a try. It supports all the same Chrome extensions, with none of the telemetry. It auto-blocks ads and helps support content creators like me.

Give the Brave browser a try »

Profile image of Mattias Geniar

Mattias Geniar, April 10, 2020

Follow me on Twitter as @mattiasgeniar

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.

HTTP/3 enabled in Firefox

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.

Enable HTTP/3 in Firefox

Refresh your site and it should show HTTP/3 in the inspector. Make sure the Protocol column is shown.

HTTP/3 enabled in Firefox

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?



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.