Nginx+NLBでHTTP/3環境をAWSに作ってみた
もこ@札幌オフィスです。
つい最近、(2019/10)CloudFlareがQUIC対応のQuicheをNginxで利用出来るパッチを公開したりHTTP-over-QUICがHTTP/3に改名したりで、HTTP/3がかなりアツくなってきています。
このビッグウェーブに乗るべく、CloudFlareのQuicheパッチを適用したNginxを用意して、NLB越しでHTTP/3を喋ってみたいと思います。
AWS環境
NLBの下にEC2を置くシンプルな構成です。
NLBでは TCP_UDP で 443 を開け、EC2を追加したターゲットグループを設定します。
Route53でNLBに対してAliasレコードを作成します。
下ごしらえ
Nginxのビルド、証明書の発行、Nginxの実行もすべてAmazon Linux 2で行っていきます。
まずはじめに、証明書とNginxをビルドする環境を用意します。
証明書を用意する
オレオレ証明書でもなんでもいいとは思いますが、折角なのでLet's Encryptで証明書を発行していきます。
certbotをインストールして、DNS検証で証明書を発行します。
1 2 | $ sudo yum install certbot -y$ sudo certbot certonly --manual -d quic.mokomoko.dev --preferred-challenges dns |
TXTレコードを設定するように言われますので、Route53でレコードを追加してDNS検証を完了させます。
Nginx(+quiche)をビルドする環境を用意
一部EPELで取得するので、 amazon-linux-extras でEPELを有効化しましょう。
1 2 3 4 5 | $ # EPELリポジトリを有効化する$ sudo amazon-linux-extras install -y epel$ sudo yum update -y $ # 必要なパッケージをまとめてインストール$ sudo yum install git patch gcc pcre-devel zlib-devel cmake3 gcc-c++ libunwind-devel golang cargo llvm7.0 -y |
Nginxを用意する
CloudFlareのブログで詳細に書かれていますので、基本的にはこちらの手順通りにやっていきますが、--prefix と --sbin-path はCloudFlareのブログで紹介されてる内容から少し書き換えています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | $ curl -O https://nginx.org/download/nginx-1.16.1.tar.gz$ tar xvzf nginx-1.16.1.tar.gz$ git clone --recursive https://github.com/cloudflare/quiche$ cd nginx-1.16.1 $ patch -p01 < ../quiche/extras/nginx/nginx-1.16.patch$ ./configure \ --prefix=/etc/nginx \ --sbin-path=/usr/sbin/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_v3_module \ --with-openssl=../quiche/deps/boringssl \ --with-quiche=../quiche$ sed -i -e 's/cmake/cmake3/g' objs/Makefile$ make$ sudo make install$ sudo mkdir /var/log/nginx$ # 確認$ sudo nginx $ curl -I http://localhostHTTP/1.1 200 OKServer: nginx/1.16.1Date: Sat, 28 Dec 2019 20:21:52 GMTContent-Type: text/htmlContent-Length: 612Last-Modified: Sat, 28 Dec 2019 19:32:46 GMTConnection: keep-aliveETag: "5e07adde-264"Accept-Ranges: bytes |
nginxとquiche取得して、quicheのpatchを当ててconfigure、make、make installです。簡単ですね。
nginx.configを編集する
やっと本題です。nginx.confを編集して、HTTP/3通信を出来るようにしてみましょう。
設定ファイルはこんな感じにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | $ cat /etc/nginx/conf/nginx.confevents { worker_connections 1024;}error_log /var/log/nginx/error.log;http { access_log /var/log/nginx/access.log; server { # Enable QUIC and HTTP/3. listen 443 quic reuseport; ssl_certificate /etc/letsencrypt/live/quic.mokomoko.dev/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/quic.mokomoko.dev/privkey.pem; # Enable all TLS versions (TLSv1.3 is required for QUIC). ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Add Alt-Svc header to negotiate HTTP/3. add_header alt-svc 'h3-23=":443"; ma=86400'; location / { root html; index index.html index.htm; } }} |
接続確認
cURLを使ってテストしてみます。
brewを使うと簡単にHTTP/3 Supprtのcurlが手に入るようなので、楽していきましょう。
HTTP/3: the past, the present, and the future
1 | $ brew install --HEAD -s https://raw.githubusercontent.com/cloudflare/homebrew-cloudflare/master/curl.rb |
コマンド一発で入れることが出来ました。
早速テストしていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | $ cd /usr/local/opt/curl/bin$ ./curl -I https://quic.mokomoko.dev/ --http3HTTP/3 200server: nginx/1.16.1date: Sun, 29 Dec 2019 01:19:54 GMTcontent-type: text/htmlcontent-length: 612last-modified: Sat, 28 Dec 2019 19:32:46 GMTetag: "5e07adde-264"alt-svc: h3-23=":443"; ma=86400accept-ranges: bytes$ ./curl https://quic.mokomoko.dev/ --http3<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; }</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.</p><p>For online documentation and support please refer toCommercial support is available at<p><em>Thank you for using nginx.</em></p></body></html> |
HTTP/3で通信することが出来ました。
アクセスログでも正常にHTTP/3になっていることを確認できます!
1 | xxx.xxx.xxx.xxx - - [29/Dec/2019:01:27:53 +0000] "GET / HTTP/3" 200 612 "-" "curl/7.68.0-DEV |
追記
Network Load BalancerのUDPのルーティングは下記のような仕様となっているようですが、ご指摘いただいてる通り、NLBを挟むだけでは完全なHTTP/3のロードバランシングは難しいと実感しました。(QUICの知識不足でした..。)
UDP トラフィックの場合、ロードバランサーは、プロトコル、送信元 IP アドレス、送信元ポート、宛先 IP アドレス、および宛先ポートに基づいて、フローハッシュアルゴリズムを使用してターゲットを選択します。UDP フローは送信元と宛先が同じであるため、その存続期間を通じて一貫して単一のターゲットにルーティングされます。異なる UDP フローは異なる送信元 IP アドレスとポートを持つため、それらは異なるターゲットにルーティングできます。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/introduction.html
また後日詳細について検証したいと思います。
まとめ
CloudFlareが提供しているNginxのパッチを利用して、NLB越しでもHTTP/3で通信することができました。
まだまだHTTP/3をフル活用したサイトが現れることは無いとは思いますが、NLB越しでAuto Scalingする環境でも利用できるかと思います。(要検証(追記))
今後のHTTP/3の動向に期待です。
おまけ(しょうもないハマった内容)
NLBがUDPを使えることしか考えていませんでしたが、きちんとEC2のSecurity GroupでUDPを開放してあげましょう。
(普段UDP使わないせいか、443(TCP)開けてるのになんで疎通できないんや!と15分くらい溶けたとか絶対言えない)
参考
https://japan.zdnet.com/article/35128543/ https://qiita.com/inductor/items/61b824289ac9b2f11b3e https://blog.cloudflare.com/experiment-with-http-3-using-nginx-and-quiche/ https://bagder.gitbook.io/http3-explained/ja