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: //localhost HTTP /1 .1 200 OK Server: nginx /1 .16.1 Date: Sat, 28 Dec 2019 20:21:52 GMT Content-Type: text /html Content-Length: 612 Last-Modified: Sat, 28 Dec 2019 19:32:46 GMT Connection: keep-alive ETag: "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.conf events { 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/ --http3 HTTP /3 200 server: nginx /1 .16.1 date : Sun, 29 Dec 2019 01:19:54 GMT content- type : text /html content-length: 612 last-modified: Sat, 28 Dec 2019 19:32:46 GMT etag: "5e07adde-264" alt-svc: h3-23= ":443" ; ma=86400 accept-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 and working. Further configuration is required.< /p > <p>For online documentation and support please refer to Commercial 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