HTTP/3対応のcurlをUbuntu 20.04で構築する（Docker版）

### 概要

以前、「[HTTP/3対応のNginxをUbuntu 20.04で構築する（Vagrant版）](https://qiita.com/akase244/items/09d0898e51cf1b0faad7)」という記事を書きましたが、記事の内容と同じ手順でHTTP/3対応のcurlコマンドをインストールしようとすると、依存するパッケージのバージョン等が変更になっておりインストールできなかったため、今回はVagrantではなくDocker環境での構築手順をまとめてみました。

### 動作環境
- ホストOS: Ubuntu 20.04 LTS
    - Docker: 20.10.7
- Dockerコンテナ: Ubuntu 20.04 LTS
    - curl: 8.0.0-DEV

### Dockerコンテナ環境の準備

Dockerレジストリからイメージを取得します。

```
$ docker pull ubuntu:20.04
```

DockerイメージからDockerコンテナを起動します。

```
$ docker container run \
--rm \
-it ubuntu:20.04 \
bash
```

各パッケージを更新します。

```
# apt -y update
# apt -y upgrade
```

### 以降の手順で必要なパッケージを事前にインストール

インストールの途中で「tzdata」の設定のために入力を求められるので、「6. Asia」、「79. Tokyo」を選択する。

```
# apt -y install \
cmake \
ninja-build \
make \
gcc \
g++ \
libunwind-dev \
git
・
・
Configuring tzdata
------------------

Please select the geographic area in which you live. Subsequent configuration questions will narrow
this down by presenting a list of cities, representing the time zones in which they are located.

  1. Africa   3. Antarctica  5. Arctic  7. Atlantic  9. Indian    11. SystemV  13. Etc
  2. America  4. Australia   6. Asia    8. Europe    10. Pacific  12. US
Geographic area: 6

Please select the city or region corresponding to your time zone.

  1. Aden         19. Chongqing    37. Jerusalem     55. Novokuznetsk   73. Taipei
  2. Almaty       20. Colombo      38. Kabul         56. Novosibirsk    74. Tashkent
  3. Amman        21. Damascus     39. Kamchatka     57. Omsk           75. Tbilisi
  4. Anadyr       22. Dhaka        40. Karachi       58. Oral           76. Tehran
  5. Aqtau        23. Dili         41. Kashgar       59. Phnom_Penh     77. Tel_Aviv
  6. Aqtobe       24. Dubai        42. Kathmandu     60. Pontianak      78. Thimphu
  7. Ashgabat     25. Dushanbe     43. Khandyga      61. Pyongyang      79. Tokyo
  8. Atyrau       26. Famagusta    44. Kolkata       62. Qatar          80. Tomsk
  9. Baghdad      27. Gaza         45. Krasnoyarsk   63. Qostanay       81. Ujung_Pandang
  10. Bahrain     28. Harbin       46. Kuala_Lumpur  64. Qyzylorda      82. Ulaanbaatar
  11. Baku        29. Hebron       47. Kuching       65. Rangoon        83. Urumqi
  12. Bangkok     30. Ho_Chi_Minh  48. Kuwait        66. Riyadh         84. Ust-Nera
  13. Barnaul     31. Hong_Kong    49. Macau         67. Sakhalin       85. Vientiane
  14. Beirut      32. Hovd         50. Magadan       68. Samarkand      86. Vladivostok
  15. Bishkek     33. Irkutsk      51. Makassar      69. Seoul          87. Yakutsk
  16. Brunei      34. Istanbul     52. Manila        70. Shanghai       88. Yangon
  17. Chita       35. Jakarta      53. Muscat        71. Singapore      89. Yekaterinburg
  18. Choibalsan  36. Jayapura     54. Nicosia       72. Srednekolymsk  90. Yerevan
Time zone: 79
・
・
done.
```

### Goをインストール

必要なパッケージをインストールします。

```
# apt -y install curl
```

Ubuntu 20.04の apt でインストールされる golang のバージョンは 1.13.8 となり、BoringSSLインストール時の `ninja` コマンド実行時に「 `note: module requires Go 1.19` 」とメッセージが表示されビルドに失敗するため、ここでは Goの1.20.1をインストールします。
※インストール手順については https://go.dev/doc/install を参考にする。

```
# cd ~
# curl -LO https://go.dev/dl/go1.20.1.linux-amd64.tar.gz
# rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.1.linux-amd64.tar.gz
# export PATH=$PATH:/usr/local/go/bin
# go version
go version go1.20.1 linux/amd64
```

### BoringSSLをインストール

「[Building BoringSSL](https://boringssl.googlesource.com/boringssl/+/HEAD/BUILDING.md)」の[Building](https://boringssl.googlesource.com/boringssl/+/HEAD/BUILDING.md#building)の手順のとおりにインストールを行います。

```
# cd ~
# git clone https://boringssl.googlesource.com/boringssl
# cd boringssl
# mkdir build && cd $_
# cmake -GNinja ..
# ninja
```

インストール後にテストを行う場合は「[Running Tests](https://boringssl.googlesource.com/boringssl/+/HEAD/BUILDING.md#running-tests)」を参考に行います。

```
# cd ..
# ninja -C build run_tests
```

### Rustをインストール

quicheインストール時の `cargo build` コマンド実行時に「 `cannot be built because it requires rustc 1.66 or newer` 」とメッセージが表示されビルドに失敗するため、ここでは、rustcをインストールします。
※インストール手順については https://www.rust-lang.org/tools/install を参考にする。

インストールの途中でオプション選択を求められるので「1) Proceed with installation (default)」を選択する。

```
# cd ~
# curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh
・
・
Current installation options:


   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1
・
・
Rust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).

To configure your current shell, run:
source "$HOME/.cargo/env"
```

パスを通してバージョンを確認する。

```
# source "$HOME/.cargo/env"
# rustc --version
rustc 1.67.1 (d5a82bbd2 2023-02-07)
```

### quicheをインストール

必要なパッケージをインストールします。

```
# apt -y install cargo autoconf libtool
```

quicheのインストールを行います。
今回は「[quiche version](https://github.com/curl/curl/blob/master/docs/HTTP3.md#quiche-version)」の手順に従ってインストールを行います。

```
# cd ~
# git clone --recursive https://github.com/cloudflare/quiche
# cd quiche
# cargo build --package quiche --release --features ffi,pkg-config-meta,qlog
# mkdir quiche/deps/boringssl/src/lib
# ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/
'quiche/deps/boringssl/src/lib/libssl.a' => 'target/release/build/quiche-cf9311eda215b807/out/build/libssl.a'
'quiche/deps/boringssl/src/lib/libcrypto.a' => 'target/release/build/quiche-cf9311eda215b807/out/build/libcrypto.a'
```

### HTTP/3に対応した curl コマンドをインストール

必要なパッケージをインストールします。

```
# apt -y install pkg-config
```

今回は「[quiche version](https://github.com/curl/curl/blob/master/docs/HTTP3.md#quiche-version)」の手順に従ってインストールを行います。

```
# cd ~
# git clone https://github.com/curl/curl
# cd curl
# autoreconf -fi
# ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-openssl=$PWD/../quiche/quiche/deps/boringssl/src --with-quiche=$PWD/../quiche/target/release
・
・
  WARNING:  HTTP3 enabled but marked EXPERIMENTAL. Use with caution!
# make
# make install
```

src ディレクトリ配下にHTTP/3対応の curl コマンドがインストールされたことを確認します。

```
# ./src/curl --version
curl 8.0.0-DEV (x86_64-pc-linux-gnu) libcurl/8.0.0-DEV BoringSSL quiche/0.16.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS HSTS HTTP3 HTTPS-proxy IPv6 Largefile NTLM NTLM_WB SSL threadsafe UnixSockets
```

### HTTP/3対応の curl コマンドでHTTPリクエストを実行

先程インストールしたHTTP/3に対応した curl コマンドに「--http3」オプションを付与してリクエストを行うと、「HTTP/3 200」という結果が返ってくることが確認できました。

```
# ./src/curl -I https://www.cloudflare.com/ja-jp/ --http3
HTTP/3 200 
date: Mon, 06 Mar 2023 06:16:46 GMT
content-type: text/html; charset=utf-8
・
・
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
```

### 参考URL

- [HTTP/3対応のNginxをUbuntu 20.04で構築する（Vagrant版）](https://qiita.com/akase244/items/09d0898e51cf1b0faad7)