nginxでQUICに対応したwebサーバーを作る (original) (raw)

こんにちは、技術部ネットワーク課の上曽山です。
新しいプロトコルとして注目を集めているQUICですが、私はこれまでほとんど触れた事がなかったため、入門編としてnginxでQUICに対応したwebサーバーを構築してみました。

QUICについて現時点で把握している事は以下の点です。語れるほどの知見が無いので詳細はwikipediaでご確認いただけると幸いです。
https://ja.wikipedia.org/wiki/QUIC

インストール可能なnginxのバージョン

今回使用するサーバーのOSはRocky Linux 9.4です。
まずは標準リポジトリからインストール可能なnginxのバージョンを確認してみます。

Last metadata expiration check: 0:00:05 ago on Thu 26 Sep 2024 10:01:09 PM JST. Available Packages nginx.x86_64 1:1.20.1-16.el9_4.1 appstream

ちょっと古いバージョンが出てきました。
dnfのモジュールを変更してより新しいnginxがインストール出来るか確認してみます。

Last metadata expiration check: 0:09:40 ago on Thu 26 Sep 2024 10:01:09 PM JST. Rocky Linux 9 - AppStream Name Stream Profiles Summary nginx 1.22 common [d] nginx webserver nginx 1.24 common [d] nginx webserver

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled

残念、1本足りなかった。標準リポジトリからは、お目当てのバージョンがインストール出来ないようです。QUIC対応のnginxをインストールするため公式サイトで公開しているリポジトリを設定することにします。

以下の設定を/etc/yum.repos.d/nginx.repoとして追加します。
どうせなら最新版を使いたいので[nginx-mainline]の「enabled=0」となっている所を「enabled=1」にしておきましょう。

[nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true

[nginx-mainline] name=nginx mainline repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true

リポジトリ設定が終わったらパッケージをインストールします。

Last metadata expiration check: 0:29:22 ago on Thu 26 Sep 2024 09:59:41 PM JST. Dependencies resolved.

Package Architecture Version Repository Size

Installing: nginx x86_64 1:1.27.1-1.el9.ngx nginx-mainline 996 k

Transaction Summary

Install 1 Package  (以下、省略)

ver1.27.1がインストール出来ました。

nginx version: nginx/1.27.1

QUICに対応したnginxの設定

公式のサンプル設定をアレンジして使用します。
今回使う設定ではserverディレクティブの部分を抜き出して/etc/nginx/conf.d/quic.confとして追加しています。
# テスト用なので最低限の設定しか入っていません。

server {

listen 8443 quic reuseport;
listen 8443 ssl;

ssl_certificate     /etc/pki/tls/certs/fullchain.crt;
ssl_certificate_key /etc/pki/tls/private/private.key;

location / {

    add_header Alt-Svc 'h3=":8443"; ma=86400';
    root /var/www/html;
}

}

アクセステスト用にindex.htmlを作成しておきます。

まず、設定ファイルの内容に間違いがないか構文チェックをしましょう。

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

チェック結果に間違いが無ければサービスを起動します。

アクセス状況を確認する

webサーバーにアクセスする前にCtrl+Shift+iでデベロッパーツールを起動して「ネットワーク」タブを開いておきます。

パケットをキャプチャしてアクセス状況を確認するため、WiresharkのCLI版をインストールします。

Last metadata expiration check: 0:49:26 ago on Thu 26 Sep 2024 09:59:41 PM JST. Dependencies resolved.

Package Architecture Version Repository Size

Installing: wireshark-cli x86_64 1:3.4.10-6.el9 appstream 20 M Installing dependencies: libsmi x86_64 0.4.8-30.el9 appstream 2.1 M

Transaction Summary

Install 2 Packages  (以下、省略)

インストールが終わったら、port 8443のパケットをキャプチャするため以下のコマンドを実行します。

Running as user "root" and group "root". This could be dangerous. Capturing on 'eth0'

結果①: デベロッパーツールの表示

結果②: パケットキャプチャの結果
# IPアドレスは修正してあります。

tshark -f "port 8443"

Running as user "root" and group "root". This could be dangerous. Capturing on 'eth0' 1 0.000000000 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TCP 66 52535 → 8443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1 2 0.000053511 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TCP 66 8443 → 52535 [SYN, ACK] Seq=0 Ack=1 Win=32120 Len=0 MSS=1460 SACK_PERM=1 WS=128 3 0.000566312 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TCP 60 52535 → 8443 [ACK] Seq=1 Ack=1 Win=2102272 Len=0 4 0.002508796 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TLSv1 2101 Client Hello 5 0.002532789 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TCP 54 8443 → 52535 [ACK] Seq=1 Ack=2048 Win=31872 Len=0 6 0.003183784 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TLSv1.3 298 Server Hello, Change Cipher Spec, Application Data, Application Data 7 0.004330802 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TCP 66 52536 → 8443 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1 8 0.004351746 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TCP 66 8443 → 52536 [SYN, ACK] Seq=0 Ack=1 Win=32120 Len=0 MSS=1460 SACK_PERM=1 WS=128 9 0.004716759 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TCP 60 52536 → 8443 [ACK] Seq=1 Ack=1 Win=2102272 Len=0 10 0.004994324 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TLSv1.3 118 Change Cipher Spec, Application Data 11 0.005343163 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TLSv1.3 341 Application Data 12 0.006543627 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TLSv1 2069 Client Hello 13 0.006567335 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TCP 54 8443 → 52536 [ACK] Seq=1 Ack=2016 Win=31872 Len=0 14 0.007022485 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TLSv1.3 298 Server Hello, Change Cipher Spec, Application Data, Application Data 15 0.015946974 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TLSv1.3 809 Application Data 16 0.016176939 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TLSv1.3 346 Application Data 17 0.016267019 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 TLSv1.3 118 Change Cipher Spec, Application Data 18 0.016402416 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 TLSv1.3 341 Application Data 19 0.034615510 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 QUIC 1292 Initial, DCID=8f01bae40f0809e3, PKN: 1, CRYPTO 20 0.034615648 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 QUIC 1292 Initial, DCID=8f01bae40f0809e3, PKN: 2, CRYPTO, CRYPTO, CRYPTO, CRYPTO, PADDING, CRYPTO, PING, PADDING, CRYPTO 21 0.035015251 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 QUIC 93 Initial, SCID=00000000000010068ffd45fec76a46058978366e, PKN: 0, ACK 22 0.035554403 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 QUIC 1242 Handshake, SCID=00000000000010068ffd45fec76a46058978366e 23 0.036424482 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 QUIC 214 Protected Payload (KP0), DCID=00000000000010068ffd45fec76a46058978366e 24 0.036578232 xxx.xxx.xxx.100 → xxx.xxx.xxx.1 QUIC 539 Protected Payload (KP0), DCID=00000000000010068ffd45fec76a46058978366e 25 0.036762955 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 QUIC 397 Protected Payload (KP0) 26 0.036887297 xxx.xxx.xxx.1 → xxx.xxx.xxx.100 QUIC 694 Protected Payload (KP0)

結果①、結果②、どちらも最初はTCP(http/1.1)でアクセスを行い、途中からQUIC(h3)に変わっている様子が確認できます。
# h3はHTTP/3(HTTP over QUIC)の意
最初にTCPで通信するのは、ブラウザはサーバーがQUICに対応している事を知らないからです。

location / {

    add_header Alt-Svc 'h3=":8443"; ma=86400';
    root /var/www/html;
}

nginxの設定でAlt-Svcヘッダーを付加するようにしているため、1度アクセスしてヘッダー情報を受信すると次からはQUIC(h3)で通信するようになります。

最後に

すごく浅い部分だけですが、QUICで通信している様子を実際に確認する事が出来ました。
引き続き、パケットを解析したりしてQUICの実装について理解を深めていきたいと思います。