ひとつのサーバで複数ドメインのSSL証明書を使いたい

BUFFALO IEEE802.11n/g/b USB2.0用 無線プリントサーバー LPV4-U2-300S

1台のサーバ(ひとつのグローバルIP)で複数ドメインのSSL証明書を使うためには、ひと工夫する必要があります。 複数ドメインのSSL証明書を使う設定を単純に書いた場合、Webサーバは、複数ドメインのうちどれかひとつにのみアクセスを振り分けるような振る舞いをします(少なくともnginxでは)。これは、SSLの仕組みが原因です。

SSLの仕組みによって通信自体が暗号化されるため、複数ドメインからのアクセスをひとつのグローバルIPアドレスで受け付けたとき、アクセスを受けたサーバはどのドメインへのアクセスなのか判断出来ません。よって、どの証明書を使えば良いのかわかりません。どの証明書を使えば良いのか判断するためには暗号化を解除する必要があるのですが、暗号化を解除するためには、どの証明書を使えば良いのか分からないといけません。鶏と卵です。

nginxは、複数のSSL証明書の定義のどちらを読み込めば分からないため、デフォルトの証明書を読み込みます。デフォルトの証明書は先に定義された証明書なので、confで先に書かれた443ポートの証明書で常に複合化を試みるという挙動をします。

解決策を考えたり調べたところ、以下の4通りになりました。

1)ドメイン毎に違うグローバルIPを用意する

別々のグローバルIPを用意し、それらすべてへのアクセスを1台のサーバに振り分ければ、どのドメインへのアクセスなのかが判断できて問題は解決です。しかし、グローバルIPを維持するためには通常費用が発生するので、多少のサーバコスト上昇を受け入れる必要があります。

2)ワイルドカード証明書を使う

もし複数ドメインがすべてサブドメインなのであれば、ワイルドカード証明書1枚にまとめることができます。ワイルドカード証明書は発行手数料が割高ですけど、Let’s encryptであれば無料で発行できます。しかしこの方法は、複数ドメインがあるドメインのサブドメインに収まる場合限定なので、もし別ドメインを追加することになったりすると面倒です。

3)マルチドメイン証明書を使う(SANs)

一枚で複数ドメインの証明書になるという直球の解決策がこのマルチドメイン証明書です。SANは「Subject Alternative Names」の略で、「サブジェクトの別名」として複数のドメイン名が登録されます。ただ、その証明書で扱いたいドメインが増えたら都度証明書を作り直す必要があるため、場合によっては運用コストがかかるし、オペレーションミスをすると面倒そうです。

4)SNIを使う(拡張SSL)

マルチドメイン証明書の運用負担を解決するのがSNI(Server Name Indication)です。SSL通信の際に、通信したいサーバのドメイン名を伝えるという仕組みです。使いたいドメイン名が分かれば、Webサーバはどの証明書を使えば良いかわかります。しかし、WindowsXPなど、いくつかのブラウザ・環境に非対応です。

https://ja.wikipedia.org/wiki/Server_Name_Indication
Internet Explorer 6 もしくはWindows XP以前での全バージョン
Safari (Windows XP上)
BlackBerry ブラウザ (7.1またはそれ以前)
Windows Mobile 6.5[38]
Android 2.x のブラウザ[39] (Honeycomb for tablets と Ice Cream Sandwich for phones では対応)
wget 1.14未満 (パッチによって対応可)

ここでは3)のマルチドメイン証明書を使うことにしました。現状、使いたいドメインの追加修正頻度は現状相当低く、運用コストの増加は心配しなくてよいという判断です。更に、 Let’s encryptでマルチドメイン証明書を簡単に発行できました。証明書を発行するときに、ドメイン名全てをカンマ区切りで指定するだけです。

https://letsencrypt.jp/faq/
1枚で複数のドメイン名に対応する証明書は発行できますか?
はい。
サブジェクトの代替名(SAN : Subject Alternative Name)という仕組みを使用することで、複数の異なるドメイン名で、同じ SSL/TLS サーバ証明書を使用することが可能です。
Let’s Encrypt クライアントソフトウェアの実行オプションで複数のドメイン名を指定することで、複数ドメインに対応した証明書を発行することができます。