Apache2 における共有 SSL 機能の実装

Apache2 において、よくレンタルサーバ等で利用されている共有 SSL 機能を簡単に実装できることがわかったので、そのメモです。(説明は良いからすっとばして設定方法へ進む)

そもそも共有 SSL の存在意義ですが、現時点での SSL の実装では、URL も暗号化されて来るため、ウェブサーバ側では実際に暗号を複合してみないと、どの URL にアクセスしてきているのかわかりません。

つまり、単一 IP アドレスしか持たないサーバでは、名前ベースのバーチャルホストで複数の SSL サイトを実現することは出来ません。

何とかして、単一ウェブサーバで複数ドメインの SSL を実装する方法としては、

  • SSL コモンネーム毎に、IP アドレスを割り当てる。
  • SSL コモンネーム毎に、ポート番号を変更する。
  • SAN を含む SSL 証明書 (いわゆるマルチドメイン SSL 証明書) を使う。
  • SNI を使用する。

が考えられます。

最初の方法は SSL 対応すべきコモンネームが必要な個数分の IP アドレスが必要で、現時点での IPv4 の枯渇からして厳しいし、中間の方法は、2 個目のコモンネームから標準的では無いポート番号でのアクセスになるため、環境によってはアクセスできない可能性がある等の理由で現実的ではありません。

SAN を含む SSL 証明書を使うの方法は一見上手くいけそうですが、前提としてブラウザ側が SAN に対応していなければならないし、しかもその単一のバーチャルホストの定義で、証明書に含まれている分の複数のコモンネームでアクセスしてもエラーにならない、と言うことだけあって、名前ベースのバーチャルホストが出来るわけでは無いので、どのみち目的は果たせません。(という認識なのですが、間違っていたらコメントで突っ込みをいただけると嬉しいです)

本命は、SNI を使用する方法なのですが、これも、ブラウザ側の対応と、サーバ側では Apache 2.2.12 以降が必要なので、みんなが SNI 対応ブラウザを使うまで待つしか無いです。

で、前置きが非常に長くなりましたが、SNI 対応クライアント環境の普及や、IPv4 でのアクセスが主流の現時点においての妥協策としては、共有 SSL の実装が無難と考えられます。しかも、先にも書いたとおり、その方法もそんなに難しくないです。(環境は、例によって Debian GNU/Linux 6.0 + Apache 2.2.16 です)

なお、以下のような共有 SSL の設定を想定します。既にバーチャルホストは設定されているものとします。

http://www.example.com/ の共有 SSL での表示は、https://ssl.example.jp/www.example.com/
http://www.example.net/ の共有 SSL での表示は、https://ssl.example.jp/www.example.net/

  • /etc/apache2/mods-available/proxy.conf ファイルを下記のように設定します。

    ProxyRequests Off
    ProxyVia On #こちらは必須では無い。

    基本的に Debian GNU/Linux 6.0 の apache2 においてはデフォルトのままで OK 。

  • 以下のコマンドを入力して 必要な proxy モジュールを有効にします。

    # a2enmod proxy proxy_http
  • https://ssl.example.jp/ を定義しているバーチャルホスト設定部分で下記を追加します。

    ProxyPass /www.example.com/ http://www.example.com/
    ProxyPass /www.example.net/ http://www.example.net/

これで、Apache2 を再起動することで、https://www.example.jp/www.example.com/ にアクセスすると、サーバ内部で http://www.example.com/ へアクセスが行われるため、上記ドメインで、http://www.example.com/ と同一のコンテンツ内容が表示されます。また、www.example.net についても同様です。

注意点としては下記があります。

  • アクセス元がサーバ自身となる。(しかし アクセス元が自サーバであった場合に、HTTP_X_FORWARDED_FOR 変数を参照することで、アクセス元はわかる)
  • 自分自身のサーバ内で完結すること。(他のサーバをアクセス先にすると、リバースプロキシを設定したサーバと他のサーバ感の間の通信は HTTP となり暗号化されない)
  • URL の階層が非 SSL でのアクセスの場合と SSL のそれとでずれる。(これは、ワイルドカード SSL と mod_rewrite を使えば解決できそうだが、携帯電話からのアクセスに対応できないと思われる)

上記中、特に、自分自身のサーバ内で、非 SSL 部分となる通信を完結することは重要です。

Apache2 における共有 SSL 機能の実装” への2件のコメント

  1. > SAN を含む SSL 証明書を使うの方法は一見上手くいけそうですが、前提としてブラウザ側が SAN に対応していなければならないし、しかもその単一のバーチャルホストの定義で、証明書に含まれている分の複数のコモンネームでアクセスしてもエラーにならない、と言うことだけあって、名前ベースのバーチャルホストが出来るわけでは無いので、どのみち目的は果たせません。

    こちらですが、名前ベースのバーチャルホストでできてます。

    ServerName ssl1.example.com
    DocumentRoot /var/www/ssl1
    SSLCertificateFile ssl.crt
    SSLCertificateKeyFile ssl.key

    ServerName ssl2.example.net
    DocumentRoot /var/www/ssl2
    SSLCertificateFile ssl.crt
    SSLCertificateKeyFile ssl.key

    のように同じ証明書、秘密鍵を指定してうまく行っています。
    もちろん証明書のSANにはssl1.example.comとssl2.example.netが入っています。

    何かの助けになれば。

    • uunfo さん、情報ありがとうございます。

      SSL の仕様上、URL は暗号化されて送信されるので、SAN では SSL での名前ベースのバーチャルホストは無理なんだと思ってました。

      ちなみにではありますが、上記の件ですが、ブラウザで TLS を使用せず、SSLv3 のみにしてもいけるものでしょうか?

コメントは受け付けていません。