default VirtualHostのTLS設定が他のVirtualHostに反映される動作
Apache HTTP Serverでdefault VirtualHostのTLS設定が他のVirtualHostに反映される動作がありました。
適切にVirtualHost設定すればほぼ遭遇しない動作ですが、気になったので留意点として整理しておきます。
本記事は、そのあたりの複数VirtualHost構成時のTLS設定の留意点についてまとめたものです。
対象はhttpd2.4系です。動作確認は主にRHEL系のLinuxで行っていますが、httpdの話なのでUbuntuやBSD系でも同様です。
複数のVirtualHostを構成した際の動作全般については、別記事にまとめてあります。
※表記統一のため、本記事では”a virtual host”のことをconfig上の表記と同じ”VirtualHost”と記載します。
本記事の目的
- Apache HTTP Serverで複数VirtualHost構成時のTLS設定の留意点を把握する。
 
基本
留意点まとめ
今回、整理しておく留意点は以下です。
- 
Listen 443の場合、SSLEngine onが未定義でもTLS化されるケースがある - 
default VirtualHostのTLS設定が他のVirtualHostに反映されるケースがある
 
いずれも、適切にVirtualHost設定すればほぼ遭遇しない動作のはずですが、検証などで色々試す際に再現することがあるかもしれません。
構成例と動作
- 前提
Listen 192.168.0.1:443(<VirtualHost>外のmain server設定(グローバル))
※IPアドレスを指定せずListen 443とした場合も同様の動作となる- 192.168.0.1:443で動作するVirtualHostは2つ (どちらも
<VirtualHost 192.168.0.1:443>)- VirtualHost #1 (
ServerName vhost1.nap)
default VirtualHost(定義順が先) - VirtualHost #2 (
ServerName vhost2.nap)
non-default VirtualHost(定義順が後) 
 - VirtualHost #1 (
 - main serverにはTLS設定無し
 
 
httpd -SでVirtualHostの構成を表示すると、以下のようになる構成です。
# httpd -S VirtualHost configuration: 192.168.0.1:443 is a NameVirtualHost default server vhost1.nap (/etc/httpd/conf.d/ssl.conf:42) port 443 namevhost vhost1.nap (/etc/httpd/conf.d/ssl.conf:42) port 443 namevhost vhost2.nap (/etc/httpd/conf/vhost.conf:1) …
VirtualHostのTLS設定を変更しながら試したところ、以下の動作となりました。
“証明書”はHTTPSに用いるサーバ証明書のことです。
| No. | <VirtualHost> #1 (default) のTLS設定  | 
<VirtualHost> #2 (リクエストにマッチ※) のTLS設定  | 
適用されるTLS設定 | 
|---|---|---|---|
| 1 | 証明書1を指定SSLEngine未定義 | 
証明書2を指定SSLEngine未定義 | 
TLSあり (証明書2使用)  | 
| 2 | 証明書1を設定SSLEngine未定義 | 
無し | TLSあり (証明書1使用)  | 
| 3 | 無し | 証明書2を指定SSLEngine未定義( SSLEngine onでも同様) | 
TLS無し | 
※クライアントからのリクエストがVirtualHost #2にマッチする際の動作です。リクエストのHost:ヘッダやSNIが”vhost2.nap”のケースです。
1. Listen 443の場合、SSLEngine onが未定義でもTLS化されるケースがある
前述のNo.1、No.2では、どこにもSSLEngine onが定義されていないにも関わらず、Listen 443が定義されているとhttpdのサービスポートはHTTPS化されます。
SSLEngineを省略した場合の初期値は”off”のはずなのですが、TLSが有効化されるということです。
細かく確認していませんが、おそらく条件としては、TLS設定上必須となるSSLCertificateFile、SSLCertificateKeyFileがdefault VirtualHostに定義してあれば、このようにTLS化されるようです。
これは、SSLEngineを省略した場合の初期値”off”をオーバーライドする動作になっているように見えます。
なお、明示的にSSLEngine offを定義したり、443番以外のポートでListenした場合は、TLS化されないようです。
httpdのマニュアルに、SSLEngine onを省略してもTLS化されるケースがあるといった記載は見つけられませんでした。
Listenディレクティブの説明に、”https is the default for port 443 and http the default for all other ports. “という記載はあります。
2. default VirtualHostのTLS設定が他のVirtualHostに反映されるケースがある
複数のVirtualHostが同じIPアドレスの443/tcpポートを使用する場合(ネームベース)、default VirtualHostのTLS設定が使用されるケースがあります(3つ以上のVirtualHost構成については未確認)。
リクエストにマッチするVirtualHostにTLS設定が無くても、configの記載順で最初に定義されたdefault VirtualHostのTLS設定が使用されるというものです。
前述のNo.2のケースでは、<VirtualHost>#2にTLS設定が一切無いにも関わらず、<VirtualHost>#2宛のリクエストに対して<VirtualHost>#1のTLS設定(証明書1)が使用されます。
またNo.1のケースでは、<VirtualHost>#1と#2それぞれで異なる証明書を指定していますが、リクエストにマッチするVirtualHostの方の証明書が優先的に使用されます。SNIは機能しているようです。
逆に、No.3のケースではTLS化されませんでした。default VirtualHostにTLSの必須設定(SSLCertificateFile、SSLCertificateKeyFile)が定義されていない場合は、non-default VirtualHost側でTLS設定してもTLS化されないようです。
ネームベースのVirtualHostをTLS化する場合は、default VirtualHostのTLS設定が必須なのでしょう。
なおTLS設定以外の設定については、本記事で説明したTLS動作とは異なり、(マニュアル通りに)マッチしたVirtualHostのものが反映されます(Header Set等)。
詳細
アクセスログ
前述の動作について、httpdのデバッグログを記載しておきます。コメントは私の推測です。
前述のNo.1
- main serverのログ
 
[ssl:info] [pid 269582:tid xxxxx] [client xxx.xxx.xxx.xxx:52273] AH01964: Connection to child 0 established (server vhost.vhost1.nap:443) ↑VirtualHost #1がコネクション確立 [ssl:debug] [pid 269582:tid xxxxx] ssl_engine_kernel.c(2382): [client xxx.xxx.xxx.xxx:52273] AH02043: SSL virtual host for servername vhost2.nap found [core:debug] [pid 269582:tid xxxxx] protocol.c(2429): [client xxx.xxx.xxx.xxx:52273] AH03155: select protocol from , choices=h2,http/1.1 for server vhost2.nap ↑SNIによりVirtualHost #2にマッチング [ssl:debug] [pid 269582:tid xxxxx] ssl_engine_kernel.c(2266): [client xxx.xxx.xxx.xxx:52273] AH02041: Protocol: TLSv1.3, Cipher: TLS_AES_256_GCM_SHA384 (256/256 bits) ↑TLSネゴシエーション完了
- VirtualHost #2のログ
 
[ssl:debug] [pid 269582:tid xxxxx] ssl_engine_kernel.c(422): [client xxx.xxx.xxx.xxx:52273] AH02034: Initial (No.1) HTTPS request received for child 0 (server vhost2.nap:443) ↑VirtualHost #2がリクエストを処理
前述のNo.2
- main serverのログ
 
[ssl:info] [pid 269887:tid xxxxx] [client xxx.xxx.xxx.xxx:52349] AH01964: Connection to child 73 established (server vhost.vhost1.nap:443) [ssl:debug] [pid 269887:tid xxxxx] ssl_engine_kernel.c(2382): [client xxx.xxx.xxx.xxx:52349] AH02043: SSL virtual host for servername vhost2.nap found [core:debug] [pid 269887:tid xxxxx] protocol.c(2429): [client xxx.xxx.xxx.xxx:52349] AH03155: select protocol from , choices=h2,http/1.1 for server vhost2.nap ↑ここまではNo.1と同じ
※VirtualHost #1のログを記録し忘れたせいか、”AH02041: Protocol: TLSv1.3, Cipher: TLS_AES_256_GCM_SHA384 (256/256 bits)”のログが見当たらなかった?(No.1ではmain serverのログに記録されているが)
- VirtualHost #2のログ
 
[ssl:debug] [pid 269887:tid xxxxx] ssl_engine_kernel.c(422): [client xxx.xxx.xxx.xxx:52356] AH02034: Initial (No.1) HTTPS request received for child 75 (server vhost2.nap:80) ↑VirtualHost #2がリクエストを処理
前述のNo.3
httpdのreload時に、以下の警告あり
[ssl:warn] [pid 268640:tid xxxxx] AH01916: Init: (vhost.vhost1.nap:443) You configured HTTP(80) on the standard HTTPS(443) port!
※HTTPSアクセス不可なので、アクセス時のログは省略。
その他の構成1(default VirtualHost無し、IPベース)
参考として、別構成の場合です。
- 前提
- 基本的に前述の構成例と同じだが、以下の差異あり
- VirtualHost #1(vhost1.nap)が
<VirtualHost _default_:443>
(前述の構成例では<VirtualHost 192.168.0.1:443>だった) - この
<VirtualHost _default_:443>は、Apache HTTP Serverのデフォルトのssl.confに定義されているものと同等 
 - VirtualHost #1(vhost1.nap)が
 
 - 基本的に前述の構成例と同じだが、以下の差異あり
 
httpd -SでVirtualHostの構成を表示すると、以下のようになる構成です。
# httpd -S VirtualHost configuration: 192.168.0.1:443 vhost2.nap (/etc/httpd/conf/vhost.conf:1) *:443 vhost1.nap (/etc/httpd/conf.d/ssl.conf:42) …
この場合も、VirtualHost #1のTLS設定の有無や、VirtualHost #2のSSLEngineの有無に関わらず、VirtualHost #2でSSLCertificateFile、SSLCertificateKeyFileが定義してあれば、httpdのサービスポートはTLS化されます。
細かい条件までは未確認ですが、明示的にSSLEngine offを定義した場合には、TLS化されません。
なお、VirtualHost #1のTLS設定がVirtualHost #2に反映されることはありません。VirtualHostのIPアドレスとポート番号の組合せを超えて反映されることは無いようです。
その他の構成2(main serverでTLS設定)
- 前提
- 基本的に前述の構成例と同じだが、以下の差異あり
- VirtualHost #1(vhost1.nap)が無し(main server)
(前述の構成例では<VirtualHost 192.168.0.1:443>だった) - これは、Apache HTTP Serverのデフォルトのssl.confに定義されている
<VirtualHost _default_:443>をコメントアウトした構成と同等 
 - VirtualHost #1(vhost1.nap)が無し(main server)
 
 - 基本的に前述の構成例と同じだが、以下の差異あり
 
httpd -SでVirtualHostの構成を表示すると、以下のようになる構成です。
# httpd -S VirtualHost configuration: 192.168.0.1:443 vhost2.nap (/etc/httpd/conf/vhost.conf:1) …
この構成はマニュアル通りの動作として、main serverの設定がVirtualHostに引き継がれます。VirtualHostにある設定はmain serverの設定をオーバーライドします。TLS設定も同様です。
ただし、SSLEngineの有無に関わらず、SSLCertificateFile、SSLCertificateKeyFileが定義してあれば、httpdのサービスポートはTLS化されるという点は同様です。
細かい条件までは未確認ですが、明示的にSSLEngine offを定義した場合には、TLS化されません。
(参考)VirtualHostの構成確認とconfigダンプの方法
基本的にhttpd -SでVirtualHostの構成を確認できますが、configから確認したい場合は、httpd -t -D DUMP_CONFIG 2>/dev/null | grep -v '#'でconfigをダンプしてVirtualHostの定義順を確認できます。
参考URL
- 
VirtualHostのマッチングに関する詳細な説明はマニュアルの以下の箇所にあります。
An In-Depth Discussion of Virtual Host Matching 








