してみるテストロゴ
Apache 2.4系でHTTP/2サーバを構築してみるテスト。

HTTP/2の各種設定

続いて、HTTP/2のサーバとしての設定を行っていきたいと思います。

ここまでのインストール作業で、HTTP/1.1のサーバとして機能しているはずです。

既にApache2.4をインストールしている方

当サイトのインストール方法以外の方法でインストールした方は、nghttp2ライブラリを含んでいるか確認してください。

# ls /usr/local/apache2/modules/mod_http2.so
/usr/local/apache2/modules/mod_http2.so
# ls /usr/local/lib/libnghttp2.so
/usr/local/lib/libnghttp2.so

と出ていれば、OKのはずです。

これらのファイルが無い場合、Apache 2.4をコンパイルする前に、あらかじめ、nghttp2をコンパイルしておく必要もあります。

まだの人は以下のページを、ご覧ください。

PREV >> インストールするもの

また、HTTP/2はTLS1.2を前提としていますので、サーバ証明書をご用意ください。

CASE:有償のサーバ証明書 >> 有償の証明書発行機関から取得
CASE:無償のサーバ証明書 >> Let's Encrypt(無償の証明書発行機関)から取得

httpd.confの設定

まず、httpd.confを編集して、HTTP/2モジュール(http2_module)を読み込むように設定します。

HTTP/2モジュール(http2_module)がロードされた場合、プロトコル合意順序に関する設定などがなされるようにします。

# vi /usr/local/apache2/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
…(省略)…
LoadModule http2_module modules/mod_http2.so
<IfModule http2_module>
	LogLevel http2:info
	ProtocolsHonorOrder On
	Protocols h2c http/1.1
	H2Direct on
</IfModule>
…(省略)…

上記設定は、ログレベルはhttp2:info、プロトコル合意順序(ProtocolsHonorOrder)を有効とし、その順序(Protocols)は、h2cとhttp/1.1の順序としています。また、h2cはダイレクトモードに対応するようになります。

これは、80番ポートを利用する、全バーチャルホスト共通の設定となります。

実際のWebブラウザは、80番ポートを利用する非暗号接続の「h2c」に対応していない可能性が高いです。構築時の参考程度に考えておくといいかもしれません。

負荷分散装置といった、リバースProxyの後方で運用するWebサーバで、利用するといった用途が、メインかと思われます。

h2cを使わないなら、動作検証が終わったら,80番ポート側のh2cは削っても良いです。

続いて、TLS(SSL)側の設定も行います。

まず、443ポートのデフォルトサーバの設定

# vi /usr/local/apache2/conf/extra/httpd-ssl.conf
/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
<VirtualHost _default_:443>
	SSLEngine on
	<IfModule http2_module>
		ProtocolsHonorOrder On
		Protocols h2 http/1.1
	</IfModule>
…(省略)…
</VirtualHost>

そして、、443ポートのバーチャルホストの設定にも同様に設定します。

443ポートの向けのバーチャルホストが複数ある場合は、すべてに設定します。

# vi /usr/local/apache2/conf/extra/httpd-ssl-vhost.conf
/usr/local/apache2/conf/extra/httpd-ssl.confの一部
<VirtualHost *:443>
	SSLEngine on
    
	<IfModule http2_module>
		ProtocolsHonorOrder On
		Protocols h2 http/1.1
	</IfModule>

	DocumentRoot "/var/https/example.com/htdocs/"
…(省略)…
</VirtualHost>

こちらも、HTTP/2モジュールがロードされた場合、プロトコル合意順序を有効とし、その順序は、h2とhttp/1.1の順序としています。

TLS1.2のALPN拡張を利用するので、ダイレクトモードの設定などは必要ありません。(というかできません。)

mod_http2のディレクティブ

ここでは、最低限の設定しか紹介していませんが、HTTP/2の細かな設定を行うディレクティブが用意されています。

下記にまとめてありますので、参考にしてください。

TLS接続

HTTP/2のTLS接続は、Forward Secrecyであることが求められます。

Forward Secrecyとは、1つのTLS接続のセッションキーが解読されても、それ以外のTLS接続のセッションキーの解読につながらない状況を言います。

これを実現する暗号プロトコルはECDHEや、DHEと呼ばれる鍵交換を行う必要があります。それ以外は、Forward Secrecyを実現できません。

HTTP/2では、当然このForward Secrecyを目指しています。

そこで、HTTP/2のTLS接続(h2)では、RFC7540の末尾にあるブラックリストに掲載の暗号スイートをつかった場合、接続のエンドポイント(サーバやクライアント)は、接続エラーとして扱ってもよいとなっています。このブラックリストに載っている暗号スイートは、ECDHEとDHE以外の鍵交換方法を使った暗号スイートです。

HTTP/2に対応している世代のWebブラウザは、軒並みECDHEによる鍵交換で、AES128/256と、SHA256以上を組み合わせた暗号に対応しています。このように、すでにWebブラウザ側は準備万端ですので、どちらかといえば、サーバ側に、ForwardSecurityを強制する圧力となります。ブラックリストに載っている暗号スイートを使用した場合、いずれ、ブラウザ側がから接続エラーと認識されて、接続できないサーバになってしまう可能性があります。

手っ取り早く設定したい場合、おすすめのSSL設定は以下の通りです。

443ポートのデフォルトVirtualHost内に設定します。独断と偏見ですが、暗号スイートは強い順に並べたつもりです。

HTTP/1.1でも、Forward Secrecyを実現することはむしろ好ましいのです。この設定は、HTTP/1.1のサーバでも有用です。

# vi /usr/local/apache2/conf/extra/httpd-ssl.conf
/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
…(省略)…

HTTP/2だけを考えれば、SSLProtocolは、TLS1.2だけでいいのですが、HTTP/1.1互換のため、TLS1.0も入れています。

[2017年2月24日追記]

が見つかったため、SHA-1を含む暗号スイートの使用を停止することを推奨します。

ただし、Android4.3以前、Safari6以前を搭載した端末のうち、アクセスできなくなる可能性があります。

当然、SSLHonorCipherOrder で、暗号スイートの合意順序を有効にして、SSLCipherSuiteに、サーバとして使いたい暗号スイートを順番に記述します。

暗号スイートとは、鍵交換、鍵認証、共通鍵暗号、メッセージ署名方法といった、暗号アルゴリズム組み合わせです。

たとえば、ECDHE-ECDSA-AES256-GCM-SHA384は、鍵交換にECDHE、鍵認証にECSA、共通鍵暗号に256ビットのAES256-GCM、メッセージ署名に384ビットのSHA386を使う方法という意味になります。

TLSは、このように、鍵交換、鍵認証、共通鍵暗号、メッセージ署名方法を組み合わせて、安全なTLS接続を実現します。

暗号スイートは、強い順でも良いのですが、応用編では、適切な強度と、サーバ負荷を考えて設定する方法を紹介しています。

上記の設定には、鍵認証のアルゴリズムとして、ECDSAとか、DSSとか入っていますが、サーバ(SSL)証明書のデジタル署名がRSA方式だと、鍵認証としてRSAしか使われません。

DSSはともかく、ECDSAの証明書はなかなか高価です。

[2016年2月11日追記]

高価でしたが、過去形で語る時代となりました。ECDSA対応の証明書もLet's Encryptから無償で入手できるようになりました。

暗号鍵のビット数にもよりますが、ECDSA対応の証明書(256ビット)と、ほぼ同じ強度のRSAの証明書(3072ビット)を比べると、 サーバ側の処理が軽くなります。

一通り、設定が済んだら是非チャレンジしてみてください。

ガラケー自体は、HTTP/2に対応することはないと思いますが、ガラケー用HTTPSサーバとの共存が必要な場合もあると思います。

おすすめしませんが、もし、HTTP/2サーバのHTTP/1.1互換機能で、ガラケーのHTTPS通信に対応する場合、ガラケー用の暗号スイートを入れるとすれば、"!aNULL"の手前に入れてください。

ちなみに、手元のサーバ証明書で確認した範囲では、以下の暗号スイートが使われました。

すくなくとも、各OS/ブラウザは、表2にある暗号スイートを利用できる、といった程度の、参考にしてください。

表2:Forward Secrecyに対応したRSA暗号プロトコルと、OS/ブラウザの状況
OpenSSLでの名称 暗号スイートOS/ブラウザ
ECDHE-RSA-AES256-GCM-SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384  Android 4.4 (TLS1.2)
WIndows 10 / Internet Explorer 11 (TLS1.2)
WIndows 10 / Edge (TLS1.2)
OS X 10.11/Safari 9.0 (TLS1.2)
iOS 9 / Safari 9.0 (TLS1.2)
ECDHE-RSA-AES256-SHA384 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384  Windows 7/8/8.1 / Internet Exploler 11 (TLS1.2)
Windows Phone 8.1 Update / Internet Explorer 11 (TLS1.2)
OS X 10.9 / Safari 7 (TLS1.2)
OS X 10.10 / Safari 8 (TLS1.2)
iOS 6~8 / Safari 6~8 (TLS1.2)
ECDHE-RSA-AES128-GCM-SHA256TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 Android 5.0 (TLS1.2)
OS X / Chrome 45 (TLS1.2)
OS X / Firefox 41 (TLS1.2)
ECDHE-RSA-AES128-SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 Windows Phone 8.1 / Internet Explorer 11 (TLS1.2)
ECDHE-RSA-AES256-SHATLS_ECDHE_RSA_WITH_AES_256_CBC_SHA  Android4.0 ~ Android4.3 (TLS1.0)
Windows Vista / Internet Explorer 7 (TLS1.0)
Windows 7 / Internet Explorer 8-10 (TLS1.0)
Windows Phone 8 / Internet Explorer 9 (TLS1.0)
OS X 10.6 / Safari 5.1 (TLS1.0)
OS X 10.8 / Safari 6.0 (TLS1.0)
DHE-RSA-AES256-GCM-SHA384TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
DHE-RSA-AES256-SHA256TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 
DHE-RSA-AES128-GCM-SHA256TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
DHE-RSA-AES128-SHA256TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
DHE-RSA-AES256-SHATLS_DHE_RSA_WITH_AES_256_CBC_SHA
ECDHE-RSA-AES128-SHATLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
DHE-RSA-AES128-SHATLS_DHE_RSA_WITH_AES_128_CBC_SHA Android2.3 (TLS1.0)

ところで、SHA1(表2で、SHAの後に256や384といった数値がついていないもの)には、セキュリティー上の問題があるので、サーバ証明書については、SHA1の利用が収束してきています。

この流れは、サーバ証明書以外にも及んでくると思われますので、SHA1を含む暗号スイートしか使えないOS/ブラウザは、サービスの対象から徐々に外していく検討が必要でしょう。

表2にある通り、HTTP/2を使うブラウザは、軒並み、SHA256以上のハッシュ関数を使っていますから、この問題の影響はなさそうです。

なお、apple tvのiOS 9はSHA1の署名だと、接続を受け付けないようです。なお、無償で取得できる、Let's Encryptのサーバ証明書は、SHA256の署名なので、大丈夫です。(逆に、SHA256の署名だと、古いガラケーに対応していないですが…)

OCSPステープリング

OCSP(Online Certificate Status Protocol)は、TLS接続を開始する際に、サーバ証明書が失効していないかを、確認するプロトコルです。

従来の証明書失効リスト(CRL)は、全リストをダウンロードしますが、OCSPは、単一サーバの証明書についてのみダウンロードすることができるため、性能的に有利です。

ただ、OCSPも、ブラウザがOCSPサーバ(OCSP Responder)に確認のための接続を行うため、その間、どうしても時間がかかってしまいます。これをHTTPSサーバ側でキャッシュして、TLS接続開始の際に、ブラウザに提供することで、接続時間の短縮を目指したのが、OCSPステープリングです。

OCSPステープリングには、Apache HTTPD Serverだと、2.3.3以降で対応しています。HTTP/2に対応している、2.4.17以降は当然対応しています。

# mkdir /var/run/ocsp
# vi /usr/local/apache2/conf/extra/httpd-ssl.conf
/usr/local/apache2/conf/extra/httpd-ssl.confの一部
…(省略)…
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLHonorCipherOrder on
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-ECDSA-AES128-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK

SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)
…(省略)…

apachctl -tで、設定ファイルの間違いが無いことを確認の上、下記のように

# /usr/local/apache2/bin/apachctl -t
Syntax OK
# /usr/local/apache2/bin/apachctl stop
# /usr/local/apache2/bin/apachctl start

再起動します。

OCSPステープリングが有効かどうかは、opensslのコマンドから調べることができます。以下は、有効な場合です。

# openssl s_client -connect example.com:443 -status
…(省略)…
OCSP response:
======================================
OCSP Response Data:
    OCSP Response Status: successful (0x0)
…(省略)…

OCSPステープリングが無効であれば、以下のようになります。

# openssl s_client -connect example.com:443 -status
…(省略)…
OCSP response: no response sent
…(省略)…

アクセスログの取り方

従来のHTTP/1.1のサーバでは、

/usr/local/apache2/conf/extra/httpd-ssl-vhost.confの一部
<VirtualHost *:443>
…(省略)…
	CustomLog "|/usr/local/apache2/bin/rotatelogs -l /var/log/https/example.com/access_log.%Y%m%d 86400" combined
	CustomLog "|/usr/local/apache2/bin/rotatelogs -l /var/log/https/example.com/ssl_request_log.%Y%m%d 86400" "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
…(省略)…
</VirtualHost>

といったフォーマットでログをとっている人が多いと思います。(このまでの説明でも上記のログ設定となっています。)

ところが、これではHTTP/2でアクセスしているにもかかわらず、

127.0.0.1 - - [05/Nov/2015:10:02:16 +0900] "GET / HTTP/1.1" 200 11170 "-" "Mozilla/5.0"

と出てしまいます。つまり、combinedに含まれる %r では、HTTP/2で繋いでも、ログにHTTP/1.1と書かれてしまいます。

上記の現象は、Apache2.4.18で解消しました。ちゃんと、combinedでも、HTTP/2と出ます。

もちろん、 %H にすれば、ちゃんとHTTP/2と表示されます。

どうせ、ssl_request_logもとるんだったら一緒にしてしまえということで、私は、以下のログフォーマットを使ってます。

Apache 2.4.18以前

非TLS(h2c)用
"%h \"%{%F %T %z}t\" - - %{pid}P %{tid}P %u %m \"%U\" \"%q\" %H %>s %B \"%{Referer}i\" \"%{User-agent}i\""
TLS(h2)用
"%h \"%{%F %T %z}t\" %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{pid}P %{tid}P %u %m \"%U\" \"%q\" %H %>s %B \"%{Referer}i\" \"%{User-agent}i\""

Apache 2.4.20以降

非TLS(h2c)用
"%h \"%{%F %T %z}t\" - - %{pid}P %{H2_STREAM_TAG}e %u %m \"%U\" \"%q\" %H %>s %B \"%{Referer}i\" \"%{User-agent}i\" %{H2_PUSHED}e %{H2_PUSHED_ON}e"
TLS(h2)用
"%h \"%{%F %T %z}t\" %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{pid}P %{H2_STREAM_TAG}e %u %m \"%U\" \"%q\" %H %>s %B \"%{Referer}i\" \"%{User-agent}i\" %{H2_PUSHED}e %{H2_PUSHED_ON}e"

 

このログフォーマットの特徴は、

  1. 従来のaccess_logになるべく似せている。
  2. といいつつIDENTは記録しない。
  3. さらに、DBに登録しやすいように日付を最初からSQLっぽくしておく。
  4. もちろん、%Hを使うことで、使用プロトコルが、HTTP/2と、ちゃんと出る。
  5. TLSのバージョンと、使用した暗号(ssl_request_logと同じ内容)を記録できる。
  6. %rを %m \"%U\" \"%q\" %H として、ログ解析しやすく分割しておく。
  7. プロセスIDとスレッドID(Aapche2.4.18以前)もしくは、StreamTag(Connection ID + Stream ID)(Apache 2.4.20以降)を記録しておくことで、適切な、ストリーム数(httpd.confのH2MaxSessionStreams)の参考にする。
  8. プッシュされたか記録(Apache 2.4.20以降)。プッシュされた場合は、プッシュ元のストリームIDを記録。

といったところです。

# vi /usr/local/apache2/conf/extra/httpd-ssl-vhost.conf
/usr/local/apache2/conf/extra/httpd-ssl.confの一部
<VirtualHost *:443>
…(省略)…
	CustomLog "|/usr/local/apache2/bin/rotatelogs -l /var/log/https/example.com/access_tls_log.%Y%m%d 86400" "%h \"%{%F %T %z}t\" %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{pid}P %{tid}P %u %m \"%U\" \"%q\" %H %>s %B \"%{Referer}i\" \"%{User-agent}i\""
…(省略)…
</VirtualHost>

次のコマンドでApacheのリスタート

# /usr/local/apache2/bin/apachctl -t
Syntax OK
# /usr/local/apache2/bin/apachctl stop
# /usr/local/apache2/bin/apachctl start

続く、HTTP/2の動作確認で、HTTP/2のアクセスを行うと、以下のように、HTTP/2と出力されます。

127.0.0.1 "2016-04-20 14:12:14 +0900" TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 24405 18-3 - GET "/css/common.css" "" HTTP/2 200 1275 "https://example.com/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36" "PUSHED" 1

完全に、好みの問題ですが、HTTP/2のログをどうしていいかわからない人におすすめです。

HTTP/2は人間からのアクセス?!

ちなみに、HTTP/2に対応してみるとよくわかるのですが、ログを見ると、人間が(ブラウザを使って)アクセスしているとHTTP/2、ロボットだとHTTP/1.1になります。

Chrome, Firefox, Internet Explorer, Microsoft Edgeいずれも、HTTP/2(h2)に対応していて、これが支配的なんですね。

ロボットもTLS1.2のALPNを設定して、次第に対応してくると思いますが、それはまだ先のことのようです。

HTTP/2へのリダイレクト

h2のサーバが安定したら、80番ポート側のバーチャルホストは、閉じたくなるのが人情。

しかし、しばらくは、検索エンジンからのアクセスも、80番経由となります。

また、ほとんどのブラウザは、優先して80番ポートに接続に来ます。これは当面、このままでしょう。

そこで、HTTP/2のサーバにリダイレクトするように設定します。ブラウザや、検索エンジンからのアクセスが、直接、HTTP/2経由になるまで待ちましょう。

# vi /usr/local/apache2/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
…(省略)…
LoadModule rewrite_module modules/mod_rewrite.so ←コメント解除
…(省略)…

次に、80番ポートのHTTPのバーチャルホストを設定します。

# vi /usr/local/apache2/conf/extra/httpd-vhosts.conf
/usr/local/apache2/conf/extra/httpd-vhosts.conf
…(省略)…
<VirtualHost *:80>
…(省略)…
    <IfModule mod_rewrite.c>
        RewriteEngine on
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    </IfModule>
…(省略)…
</VirtualHost>
…(省略)…

リダイレクトのレスポンスステータスコードは、301となるようにR=301にします。これで、検索エンジンにも、恒久的な移動であることを知らせます。

apachctl -tで、設定ファイルの間違いが無いことを確認の上、下記のように

# /usr/local/apache2/bin/apachctl -t
Syntax OK
# /usr/local/apache2/bin/apachctl stop
# /usr/local/apache2/bin/apachctl start

再起動します。これで、80番ポートに接続しても443番ポートに飛びます。

Let's Encryptのリダイレクト対応

Let's Encryptのサーバはドメイン認証の際に、HTTP/1.1⇒HTTPSのリダイレクトを経て、HTTPS側の

/.well-known/acme-challenge/

にある認証用のファイルをとってきてくれます。

そのため非暗号のHTTPに来たリクエストは、丸ごと、HTTPSに転送するようにmod_rewriteを設定してもいいのですが、HTTPSに認証用のフォルダを作成したくない時もあります。

そこで、ACME認証のみHTTPで処理し、それ以外をHTTPSに転送する設定を紹介します。

# vi /usr/local/apache2/conf/extra/httpd-vhosts.conf
/usr/local/apache2/conf/extra/httpd-vhosts.conf
…(省略)…
<VirtualHost *:80>
…(省略)…
    <IfModule mod_rewrite.c>
      RewriteEngine on
      RewriteCond %{HTTPS} off
		RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
		RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    </IfModule>
…(省略)…
</VirtualHost>
…(省略)…

apachctl -tで、設定ファイルの間違いが無いことを確認の上、下記のように

# /usr/local/apache2/bin/apachctl -t
Syntax OK
# /usr/local/apache2/bin/apachctl stop
# /usr/local/apache2/bin/apachctl start

再起動します。これで、「ACMEプロトコルにおけるドメイン認証」、以外のリクエストは、80番ポートから443番ポートに飛びます。

 

2018年1月10日に、Let's Encryptのドメイン認証方法のひとつである、TLS-SNIチャレンジ(tls-sni-01)に脆弱性が発見されたため、以下の方法は推奨できません。

 

前述の通り、80番ポートから、443番ポートのHTTPS(HTTP/2)へ、リダイレクトを行うと、非暗号(80番ポート)のHTTP/1.1のhtdocs配下は、閲覧できなくなります。

つまり、Let's Encrypt(ACMEプロトコル)が利用していた、80番ポートのバーチャルホストのhtdocs配下にコンテンツを置いても、閲覧できません。ここに、「認証ためのファイル」を設置しても、ACMEサーバから、見られなくなります。

当然、Let's EncryptのACMEサーバからの認証チャレンジが、失敗してしまいます。

そこで認証用ファイルを、HTTPS側に設置するようにします。具体的には、letsencrypt-autoの--webrootオプションを、HTTPS通信用の/var/https/example.com/htdocs/に変更します。

さらにACMEサーバに、HTTP/1.1からリダイレクトを実行するように、--rediretオプションを追加します。

仕上げに、Renewal用のファイルを更新するため、一回、以下のコマンドをコマンドラインからたたきます。

$ cd /usr/local/letsencrypt
$ ./letsencrypt-auto certonly -t -d example.com  -a webroot --webroot-path=/var/https/example.com/htdocs/ --rsa-key-size 2048 --server https://acme-v01.api.letsencrypt.org/directory --rediret

同じく、自動取得用のスクリプトも書き換えます。

# vi /usr/local/apache2/bin/cert_refresh.sh
/usr/local/apache2/bin/cert_refresh.sh
#! /bin/sh
cd /usr/local/letsencrypt
./letsencrypt-auto certonly -t -d example.com -a webroot --webroot-path=/var/https/example.com/htdocs/ --renew-by-default --server https://acme-v01.api.letsencrypt.org/directory --redirect
/usr/local/apache2/bin/apachectl restart

これで、リダイレクトして、認証してくれます。

ちなみに、HTTP/1.1でアクセスしてきますので、HTTP/1.1でもアクセスできるようにしておく必要があります。つまり、「Protocols h2 http/1.1」といった設定が、不可欠です。h2だけで運用するのは、もう少し後になりそうです。設定的には、以下のようになっているか確認してください。

# vi /usr/local/apache2/conf/extra/httpd-ssl-vhost.conf
/usr/local/apache2/conf/extra/httpd-ssl.confの一部
<VirtualHost *:443>
	SSLEngine on
    
	<IfModule http2_module>
		ProtocolsHonorOrder On
		Protocols h2 http/1.1
	</IfModule>

	DocumentRoot "/var/https/example.com/htdocs/"
…(省略)…
</VirtualHost>

HTTP Strict Transport Security(HSTS)

リダイレクトの設定をしたらなら、次に、HTTP側からHTTPS側にリダイレクトされた際に、ブラウザに次回以降、直接HTTPSにアクセスするよう、覚えてもらいます。

これをHTTP Strict Transport Security(HSTS)と呼びます。これは、リダイレクトの際に、HTTP→HTTPSと通信が切り替わるまでの間に、中間者攻撃が行われる可能性があるため、これを防ぐため、ブラウザに直接HTTPSに来てもらうように覚えてもらう仕組みです。有効期限(max-age:秒単位)と一緒に設定します。

これは、HTTPS(TLS)側のバーチャルサーバに置きます。

以下の設定では、今後180日、当該バーチャルサーバのドメインに対して、HTTPではなく、HTTPSに直接来てもらうことを覚えてもらいます。

つまり、最短で半年に1回は、HTTPへアクセスしてきますので、この設定は、リダイレクト設定とセットで、使い続けます。

まず、httpd.confを編集して、ヘッダモジュール(headers_module)を読み込むように設定します。

# vi /usr/local/apache2/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
…(省略)…
LoadModule headers_module modules/mod_headers.so
…(省略)…

続いて、次回は直接443ポートに接続するようヘッダを追加します。

# vi /usr/local/apache2/conf/extra/httpd-ssl-vhost.conf
/usr/local/apache2/conf/extra/httpd-ssl-vhost.confの一部
<VirtualHost *:443>
…(省略)…
Header add Strict-Transport-Security "max-age=15552000"
…(省略)…
</VirtualHost>

apachctl -tで、設定ファイルの間違いが無いことを確認の上、下記のように

# /usr/local/apache2/bin/apachctl -t
Syntax OK
# /usr/local/apache2/bin/apachctl stop
# /usr/local/apache2/bin/apachctl start

再起動します。これで、中間者攻撃のリスクが減りました。

無いとは思いますが、一旦、上記設定を反映後、HTTPからのリダイレクトを止めて、HTTPSとHTTPで異なるコンテンツを展開したい場合は、DNSのTTLを短縮するのと同様、事前に、max-ageの短縮を行わなければなりません。180日であれば、180日前から、短縮の必要があります。

NEXT >> HTTP/2の動作確認

©Copyrights 2015-2023, non-standard programmer

このサイトは、あくまでも私の個人的体験を、綴ったものです。 軽く参考程度にご利用ください。