概要
自前でHTTP3の検証環境を構築するために、Apple Siliconを搭載したMacでHTTP3に対応したcurlをビルドしたので、その過程などを備忘録も兼ねて残しておきます。
自分も、ネットワークなどについて特段詳しいというわけではないので、初心者と同じようにあれこれ試しながら進めた過程です。 分かりにくいところや誤った内容は、コメントなどで教えていただければ幸いです。
環境
- チップ: Apple M2
- OS: macOS 13.5
- コンパイラ: Apple clang version 15.0.0 (clang-1500.0.40.1)
周辺情報の整理
まず大前提として、デフォルトのcurlではHTTP3には対応していないようです。そのため、HTTP3に対応させるためには、自分で設定をした上でcurlをビルドする必要があります。
親切なことに、curlのリポジトリ内にはHTTP3に対応したcurlをビルドするためのドキュメントが用意されています。なので、基本はここに沿って進めていきまが、ところどころ詰まった箇所もあるので、そこを補いながら書いていければなと思っています。
周辺ライブラリについて
HTTP3及びその下層のQUICのプロトコルに対応した実装は、外部ライブラリを組み込んで機能させるようです。
本記事ではQUICの実装としてngtcp2を、HTTP3の実装としてnghttp3を使用します。このうちngtcp2のビルド時にはngtcp2のリポジトリのREADMEも参照したので、そのリンクも貼っておきます。
curlのリポジトリでは他にもQUICの実装としてquicheとmsh3が紹介されていましたが、どちらも実験段階ということなので、今回は無難にngtcp2を用いたものにしました。
併せて、QUICに対応したTLSライブラリが必要でしたので、今回はcurlのリポジトリのドキュメントでも一番上に記載のあるquictlを利用することにしました。OpenSSLというライブラリがデフォルトではQUICに対応しておらず、そこからフォークしてQUICに対応させた実装のようです。curlのリポジトリにはGnuTLSあるいはwolfSSLを用いたビルド方法も記載があります。
ビルドの実施
依存ライブラリのダウンロード
はじめにngtcp2のREADMEにビルドのために必要なライブラリが紹介されていたので、それらをダウンロードしました。記載のあったのは以下のライブラリです。
- pkg-config >= 0.20
- autoconf
- automake
- autotools-dev
- libtool
このうちautotools-devはインストール方法がわからず飛ばしたのですが、ビルドはできました。それ以外のライブラリは、以下のコマンドでインストールをしました。
brew install pkg-config
brew install autoconf
brew install automake
brew install libtool
quictlsのビルド
curlの手順書どおりにビルドしました。
ここに記載の<somewhere1>
という部分が最初なんのことか分からなかったのですが、ビルドのパスを指定して、かつ後々の手順の中で同じパスを指定してねという、変数みたいな役目で使っているようです。この先同様に<somewhere1>
が出てきたら、それはこのquictlsのビルドフォルダを指します。
git clone --depth 1 -b openssl-3.1.4+quic https://github.com/quictls/openssl
cd openssl
# ./config enable-tls1_3 --prefix=<somewhere1>
./config enable-tls1_3 --prefix=$PWD/build
make
make install
nghttp3のビルド
ここもcurlの手順書どおりにビルドしていきます。
このmake
やmake install
実行時になんだかログを吐いて最初エラーかと思いましたが、明確にErrorという表記がなければ問題なさそうです。エラーの時はいかにもなエラーが大量に出ます😨
cd ..
git clone -b v1.0.0 https://github.com/ngtcp2/nghttp3
cd nghttp3
autoreconf -fi
# ./configure --prefix=<somewhere2> --enable-lib-only
./configure --prefix=$PWD/build --enable-lib-only
make
make install
ngtcp2のビルド
ここだけcurlの手順書と少し異なった手順でビルドをしました。正確にいうと、ngtcp2のREADMEにある手順に従いました。
該当箇所のコードは以下です。色々とコメントでも書いてあります。まずPKG_CONFIG_PATH
のオプションについては下記の通り、今までビルドしてきたquictlsとnghttp3のビルドフォルダのパスを指定します。
それから、ngtcp2のREADMEの実行コマンドには、Macのユーザならいくつかのオプションを追加してね的なことが書いてあるので、それを追加します。
具体的には、LDFLAGSオプションの末尾に,-L/opt/homebrew/lib
を追記し、さらに新しくCPPFLAGS="-I/opt/homebrew/include"
というオプションを追加しました。
ngtcp2のREADMEのコマンドにはパスとして/opt/local/lib
などが記載されていましたが、AppleSiliconのコンピュータだと/opt/homebrew/lib
のようになるかなと思います。前者で記載して実行した場合、そのフォルダは空ですとwarningが出ました。
cd ..
git clone -b v1.0.1 https://github.com/ngtcp2/ngtcp2
cd ngtcp2
autoreconf -fi
# curlのREADMEに記載されているコマンドはこっち
# ./configure PKG_CONFIG_PATH=<somewhere1>/lib/pkgconfig:<somewhere2>/lib/pkgconfig LDFLAGS="-Wl,-rpath,<somewhere1>/lib" --prefix=<somewhere3> --enable-lib-only
# 公式のリポジトリにあるコンフィグコマンドはこっち
# For Mac users who have installed libev with MacPorts, append
# ',-L/opt/local/lib' to LDFLAGS, and also pass
# CPPFLAGS="-I/opt/local/include" to ./configure.
# For OpenSSL >= v3.0.0, replace "openssl/build/lib" with
# "openssl/build/lib64".
# 元のコマンド
# ./configure PKG_CONFIG_PATH=$PWD/../openssl/build/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig LDFLAGS="-Wl,-rpath,$PWD/../openssl/build/lib"
# macなので指示通りパスを追加してみる
# Apple Siliconのmacだと/opt/local/*ではなく/opt/homebrew/*かも
./configure PKG_CONFIG_PATH=$PWD/../openssl/build/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig LDFLAGS="-Wl,-rpath,$PWD/../openssl/build/lib,-L/opt/homebrew/lib" CPPFLAGS="-I/opt/homebrew/include" --prefix=$PWD/build --enable-lib-only
make
make install
curlのビルド
最後にcurl本体のビルドです。これも基本はcurlの手順書通りに実行しました。
最後のmake installだけ、そのまま実行するとエラーになってしまいました。エラー内容がインストールする権限が無いよ的なものだったため、sudoをつけて実行すると最後まで動作しました。これもAppleSilicon故の環境の違いが原因なのかなと考えています。
sudoでの実行に抵抗のある方は、実行しないままでも/src配下に実行ファイルがあるかと思うので、それを利用する形で問題ないかと思います。
cd ..
git clone https://github.com/curl/curl
cd curl
autoreconf -fi
# LDFLAGS="-Wl,-rpath,<somewhere1>/lib" ./configure --with-openssl=<somewhere1> --with-nghttp3=<somewhere2> --with-ngtcp2=<somewhere3>
LDFLAGS="-Wl,-rpath,$PWD/../openssl/build/lib" ./configure --with-openssl=$PWD/../openssl/build --with-nghttp3=$PWD/../nghttp3/build --with-ngtcp2=$PWD/../ngtcp2/build
make
# make install
sudo make install
これにてcurlをビルドすることができました。実行ファイルは/usr/local/bin/curl
もしくは、上の操作時点からフォルダを移動していなければ./src/curl
にもありました。
curlの動作確認
curlの動作を確認します。HTTP3に対応しているいずれかのサイト(記事の例ではwww.google.com)に--http3-only
と-v
のオプションをつけてcurlを実行してみます。レスポンスのボディは必要ないので、捨てています。
/usr/local/bin/curl --http3-only https://www.google.com -v 1> /dev/null
結果として、以下のような記述が見られれば成功でしょう。
* using HTTP/3
* [HTTP/3] [0] OPENED stream for https://www.google.com/
qlogファイルの出力も以下のようなコマンドでできました。
QLOGDIR=./ /usr/local/bin/curl --http3-only https://www.google.com -v 1> /dev/null
感想
完全に記事の本旨とは異なりますが、備忘録も兼ねているのでここまで作業しての私個人の感想的なものです。
自分の知識不足でもありますが、curlの中で使うQUICやHTTP3、TLSのライブラリを別でビルドして組み込むっていうことをしているんだなーと単純に感心しながらやっていました。てっきりそういう部分もcurl内で既にプログラム書かれているものかと思っていました。外部ライブラリを使うことで、実装をシンプルにかつ高機能にできるといった具合なのでしょうか。
それから、TLSのライブラリ群について、OpesSSLはこの分野あまり詳しくない自分でも名前を見聞きしたことがあるくらい主流なライブラリだと思っていたので、まさかまだQUICに対応していないとは…という気分でした。規模が大きければ大きいほど、動きづらくなってしまうということなんでしょうか。
今回はcurlのビルドでしたが、併せてはHTTP3に対応したnginxのビルドにも取り組んでいるので、その件もまたQiitaにまとめられればと思います。
参考文献・関連リンク