AmazonLinux2のhttpdをALB経由で公開するWeb環境で発生していた、SafariのHTTPS接続エラーを改善してみた
はじめに
AWSチームのすずきです。
Webサーバとして、Amazon Linux2 の httpd (Apache/2.4.37)、 ELB に HTTP/2 をサポートする Application Load Balancer (ALB) を利用する環境で、 iOS と macOS の Safari からの HTTPS 接続がエラーとなる現象を、 httpdの設定で回避する機会がありました。
その内容について紹介させていただきます。
構成
事象
Safariから HTTPS (HTTP/2) 接続時に、プロトコルエラーが発生する事がありました。
以下のサイトで紹介されていた、 iOS と、High Sierra の macOS 環境の Safari で、CentOS7 の httpd24 (Apache) を Nginx をリバースプロキシとする環境で発生する報告を参考に、 調査と対応を実施しました。
参考サイト
iPhone does not open HTTPS site in Safari with error NSPOSIXErrorDomain:100
Safari can't open the page. The error is: "The operation couldn't be completed. Protocol error" (NSPOSIXErrorDomain:100)
調査結果
Amazon Linux2 の 標準リポジトリから httpd のインストール時、 依存関係で同時にインストールされる「http2_module」により、HTTP/2 切替を促すレスポンスヘッダが、ブラウザ(Safari)の誤動作を引き起こしていました。
Installing: httpd x86_64 2.4.37-1.amzn2.0.1 amzn2-core 1.3 M Installing for dependencies: mod_http2 x86_64 1.11.1-1.amzn2 amzn2-core 150 k
HTTP/2 をサポートするALB、配下のEC2との通信は HTTP/1.1 が利用されます。
AWS ドキュメント
Application Load Balancer のリスナー
Application Load Balancer は、HTTPS リスナーに HTTP/2 のネイティブサポートを提供します。1 つの HTTP/2 コネクションで最大 128 のリクエストを並行して送信できます。ロードバランサーは、これらのリクエストを個々の HTTP/1.1 のリクエストに変換し、ターゲットグループの正常なターゲットにこれを分配します
対策
「mod_http2」のSRPMパッケージに含まれるSPECファイルより設定ファイルを特定し、 モジュールの無効化後、httpdサービスを再起動しました。
設定ファイルの特定
モジュールをロードしている 設定ファイルの10-h2.conf
の特定と、
yum update などによる設定が上書きされない事 「%config(noreplace)」を確認しました。
$ yumdownloader --source mod_http2 $ rpm -Uvh mod_http2-1.11.1-1.amzn2.src.rpm $ cat ~/rpmbuild/SPECS/mod_http2.spec | grep 10-h2.conf echo "LoadModule http2_module modules/mod_http2.so" > %{buildroot}%{_httpd_modconfdir}/10-h2.conf %config(noreplace) %{_httpd_modconfdir}/10-h2.conf
モジュールの無効化
sed -i -e "s/^LoadModule/#LoadModule/g" /etc/httpd/conf.modules.d/10-h2.conf
設定変更確認
cat /etc/httpd/conf.modules.d/10-h2.conf # LoadModule http2_module modules/mod_http2.so
httpd再起動
sudo systemctl restart httpd
レスポンス確認
変更前
$ curl -v http://localhost/ > /dev/null * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 80 (#0) > GET / HTTP/1.1 > Host: localhost > User-Agent: curl/7.61.1 > Accept: */* > < HTTP/1.1 200 OK < Date: Wed, 03 Apr 2019 09:45:31 GMT < Server: Apache/2.4.37 () < Upgrade: h2,h2c < Connection: Upgrade < Last-Modified: Thu, 10 Jan 2019 00:16:31 GMT < ETag: "e2e-57f0f7d8a35c0" < Accept-Ranges: bytes < Content-Length: 0 < Content-Type: text/html; charset=UTF-8
変更後
$ curl -v http://localhost/ > /dev/null * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 80 (#0) > GET / HTTP/1.1 > Host: localhost > User-Agent: curl/7.61.1 > Accept: */* > < HTTP/1.1 200 OK < Date: Wed, 03 Apr 2019 09:51:10 GMT < Server: Apache/2.4.37 () < Last-Modified: Thu, 10 Jan 2019 00:16:31 GMT < ETag: "0-58604a5875420" < Accept-Ranges: bytes < Content-Length: 0 < Content-Type: text/html; charset=UTF-8
レスポンスヘッダから、HTTP/2 切替を促す、Upgrade: h2,h2c
の出力がなくなりました。
まとめ
効率の良い通信が期待できる ALBの HTTP/2 サポートを無効化する事なく、一部のブラウザ(Safari)で発生していたHTTPS接続エラーを回避する事ができました。
ELB配下で利用する場合には不要な Amazon Linux2 のmod_http2 モジュール 無効化により僅かながらもトラフィックやEC2リソースの節約にもなったと推測されます。
EC2インスタンス起動時に Amazon Linux2 の httpd をインストールする場合、以下のようなユーザーデータをお試しください。
#!/bin/bash -xe # httpd install yum install -y httpd # mod_http2 off sed -i -e "s/^LoadModule/#LoadModule/g" /etc/httpd/conf.modules.d/10-h2.conf # KeepAlive On echo 'KeepAlive On' > /etc/httpd/conf.d/keepalive.conf # KeepAliveTimeout echo 'KeepAliveTimeout 120' >> /etc/httpd/conf.d/keepalive.conf # systemctl systemctl start httpd systemctl enable httpd
参考
KeepAlive 設定は、以下を参考に設定しました。
ELB のバックエンドサーバーとして Apache または NGINX を使用するための最適な設定を教えてください。