Dockerを使ってHTTP3対応のnginxでホスティングする手順
概要
HTTP3に対応したサイトが全世界のウェブサイトの中で25%あるらしいです。
nginxのroadmap上では、3年前からHTTP3が入っているのに2023年2月11日現在ではまだstableでのリリースは行われていません。
HTTP3を簡単に試してみるツール類は揃ってきているので今回は、HTTP3対応のnginxを使ってどんな感じの運用になるかをテストしてみます。
設定
前提
nginxをリバースプロクシとして動かし、バックエンドとしてlocalhostの3005番ポートでRuby on Railsサービスが動いているという前提です。
nginxにはlet’s encryptで取得したTLS証明書を使ってhttpsによる接続を行っています。
今回の対象サイト: https://train.teraren.com/
サーバサイドの設定
HTTP3のデフォルトはUDPの443番ポートを使います。もちろん443番はデフォルトなだけであるので任意のポートも利用できます。
とりあえず、以下のようなコマンドを打ち込んでみてlocalhostにてUDPの443ポートが使われていないことを確認します。
% netstat -ln | grep 443 | grep udp
次に、以下のような設定ファイルを作成します。
設定ファイルの内容は適宜変更してください。TLS証明書のファイルの場所、ドキュメントrootの場所を適宜変更します。
proxy_passに指定するバックエンドのサービスのホスト名は、docker container内から参照できるIPアドレスまたはホスト名にする必要があります。ここで、localhostと指定してもコンテナ自体のホストを指すことになってしまいますので注意してください。
そして、docker composeで立ち上げればOKです。let’s encryptのファイルの読み込みにはroot権限が必要になりますが、docker自体がroot権限で実行されるようなので一般ユーザで起動してもちゃんと読み込めてます。
% docker compose up
これで立ち上がります。
これで、1つのバックエンドサービスに対して2つのWebサーバが立ち上がっている状態になります。1つは元から動いているnginx、2つ目は今回立ち上げたHTTP3対応nginxです。
最後に、外部から接続できるようにfirewallやパケットフィルタの設定などでUDP 443への接続を許可します。
接続テスト
ブラウザ上ではhttp2もhttp3も同じURLになります。後述するalt-svcヘッダを出力する設定を元のnginx側で出力するようにする設定が必要になります(後述)
よって、まずはCLIを使ってテストしてみます。
% docker run -it --rm ghcr.io/unasuke/curl-http3:quiche-latest curl -IL https://train.teraren.com/ --http3
正常な結果
もし、HTTP3のnginxの設定が間違っていた場合は500系のエラーが返ってきます。
500系のエラー
HTTP3のnginxを立ち上げたdocker composeの標準出力にアクセスログやエラーが表示されるのでその内容をチェックすれば良いと思います。
HTTP3に対応していることをブラウザへ 告知
現時点でブラウザは、httpsスキーマが指定されたらTCP 443番に対してTLSを使って接続し、HTTP 2.0などのアプリケーションプロトコルを使って接続を試みます。
この状態では、ウェブサイトがHTTP3に対応しているかどうかわかりません。なので、このTCPで接続した際にHTTP3に対応していることをHTTPヘッダのレスポンスで返します。
以下の設定をTCPで運用している元のnginxに追加します。これにより、ブラウザはHTTP3でのサービス提供が行われているサイトということを認識できます。
add_header alt-svc 'h3=":443"; ma=3600';
外部のチェッカー
何故かエラーになる。。。(追記: 今はCloudflareに載せ替えたのでエラーになりません)
余談
自分の使っているブラウザがHTTP3に対応しているかどうかは以下のサイトなどでチェックできます。
手元のBraveブラウザではなぜかHTTP3での接続が行われない状態でした。
まとめ
- HTTP3用nginxを立ち上げると、同じような設定を2箇所で管理しないといけないので面倒です。早くstableでHTTP3を対応してほしいです。
- すでにlet’s encryptで証明書を取得している場合は簡単にHTTP3を試せます。
Discussion