[小ネタ] 今のCaddy(>=2.6.0)はudp/443が入れば無設定でHTTP/3(QUIC)できます

## Caddy 2.9.1 時点におけるHTTP/3の実装状況

現時点のCaddy (2.9.1) 時点では特にHTTP/3 (QUIC) を有効化するために **特別なディレクティブを書く必要はなく、デフォルトで有効になっています。**

厳密には **2.6.0 (2022-09リリース) からデフォルトでHTTP/3が有効** になっているようです。

https://github.com/caddyserver/caddy/releases/tag/v2.6.0

## そもそも HTTP/3 (QUIC) ってなんだっけ？

QUICはUDP上の伝送プロトコルで、設計がやや古く性能や特性に不満があるTCPの置き換えを狙うものです。TCPでは独立していたTLS（暗号化）の機能もQUICに包含されます。また、通常TCPがOSで実装されているのとは異なり、QUICはユーザーランドで実装されます。OSからは単純なUDPとして認識されます。

TCP上のプロトコルであるHTTPをQUIC上に移植したものがHTTP/3です。[Chromeなどメジャーブラウザは全てHTTP/3をサポートしています。](https://caniuse.com/?search=HTTP%2F3)

| | HTTP/1.1 | HTTP/2 | HTTP/3 |
|--|--|--|--|
| 多重転送 | なし | サポート | サポート |
| HOLブロッキング | あり | TCPレベルで存在 | QUICレベルで大幅に軽減 |
| ヘッダ圧縮 | なし | HPACK | QPACK |
| TLS | オプショナル | 事実上必須 | 必須 (QUIC) |
| 伝送プロトコル | tcp/80, tcp/443 (TLS) | tcp/80, tcp/443 (TLS) | udp/443 (QUIC) |

今日、普通にWebサーバを構築した場合、セキュリティグループには `tcp/80` と `tcp/443` を指定するだけだと思います。この場合はHTTP/2サーバとしてしか動作できません。


## 実際に Caddy が HTTP/3 を受け付けるかローカルでテストしてみる

`https://foobar.localhost` で待ち受けるCaddyを立ち上げます。

```sh
$ caddy reverse-proxy --from https://foobar.localhost --to :3100
```

`:3100` にリバースプロキシしているので、 `hello` だけ応答するサーバも `:3100` に用意してあげましょう。

```sh
$ caddy respond "hello" --listen :3100
```

これで `https://foobar.localhost` にアクセスすると `hello` と応答するサイトが用意できたので、ChromeでアクセスしてHTTP/3が使われるか確認してみます。

とはいえ、デフォルトでChromeはなかなかHTTP/3を使わないようになっているので、以下のように新規に Chrome を立ち上げ、 `foobar.localhost:443` へのリクエストはなるべくQUICを使ってもらうようにしてもらいます。

```sh
# 以下は macOS での Chrome 立ち上げです
# Windows の場合は chrome.exe に対して同じように --origin-to-force-quic-on=... のフラグを指定してください
$ open -a "Google Chrome" -n --args --origin-to-force-quic-on=foobar.localhost:443
```

立ち上がったChromeで https://foobar.localhost にアクセスしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1577592/c143f97c-f778-67ed-23a4-5bca34ada1a8.png)

インスペクターの `Network` / `Protocol` 欄に `h3` が並んでいるのがわかると思います。これがHTTP/3です。

curl でも確認してみます。とはいえ、こちらも macOS の curl (`libcurl/8.7.1`)は現時点でHTTP/3をサポートしていないので、Dockerのcurlを起動してみます。ただ、これも [公式のcurlイメージ](https://hub.docker.com/r/curlimages/curl) がHTTP/3をサポートしていないので [badouralix/curl-http3](https://hub.docker.com/r/badouralix/curl-http3) で確認します。

```sh
# Docker内部からのアクセスなので、 -k --resolve ... が必要となる
# (Docker for Macの実装がマシになったらもうちょっときれいに書けるかも)
$ docker run --rm -it badouralix/curl-http3 \
  curl --http3-only -k -v \
    --resolve foobar.localhost:443:自分のマシンのIPアドレス \
    https://foobar.localhost

* Skipped certificate verification
* Connected to foobar.localhost (自分のマシンのIPアドレス) port 443
* using HTTP/3
* Using HTTP/3 Stream ID: 0
> GET / HTTP/3
> Host: foobar.localhost
> User-Agent: curl/8.2.0-DEV
> Accept: */*
>
< HTTP/3 200
< server: Caddy
< server: Caddy
< content-type: text/plain; charset=utf-8
< date: Wed, 15 Jan 2025 09:44:55 GMT
< content-length: 5
<
* Connection #0 to host foobar.localhost left intact
hello%
```

HTTP/3 で繋げているようです。

## AWS(Lightsail)上にHTTP/3でデプロイしてみる

実際にHTTP/3を受け付けるサーバを立ててみたいと思います。

といっても、以下のような `tcp/80` `tcp/443` に加えて `udp/443` が設定されているサーバを立ち上げるだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1577592/a7c1c05d-03e1-12ca-7bbd-5b9691f29a21.png)

立ち上げたサーバに以下のCaddyfileを記入します。通常の設定と変わるところは一つもありません。

```Caddyfile:/etc/caddy/Caddyfile
{
    email ksaitou@test.example.net
}

test.example.net {
    respond "hello!"
}
```

立ち上げたサーバについて、Chrome等でアクセスするか、[Nginxが提供しているサービス](https://http3check.net/) を使って、HTTP/3導通可能かチェックします。

https://http3check.net/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1577592/be9ea9a8-c1c1-d2bc-594d-b9f1d4c46736.png)

特に問題なくHTTP/3で繋げられることが分かります。

## まとめ

2.6.0 以降のCaddyを今現在使っている場合は `udp/443` を開けるだけで HTTP/3 を今すぐ有効にすることができます。

無理をして有効にする必要もありませんが、有効になっていることによって、特に通信環境が劣悪なモバイル環境においてユーザ体験が向上する可能性があります。今後のWebサーバ構築の際は `udp/443` を最初から開いておくことも検討していいでしょう。


## 関連エントリー

https://qiita.com/ssc-ynakamura/items/2d9844f9cee709f7f8e7

https://qiita.com/ssc-ksaitou/items/1d780403cdbda3dea319