【Apache SSL講座 第5回】1つのIPで複数ドメイン!バーチャルホストでのSSL設定とSNIの仕組み完全図解

「IPアドレスが足りない!」過去の悩みを解決した救世主。

こんにちは!「LINUX工房」管理人の「リナックス先生」です。
前回は、TLS 1.3の導入やHSTS設定を行い、単一サイトのセキュリティ強度を極限まで高めました。

しかし、実際のサーバー運用では、「1台のWebサーバーで、複数のWebサイトをホストしたい」という要望がほぼ100%発生します。
例えば、linux-kobo.com(ブログ)と shop.linux-kobo.com(ショップ)、あるいは全く別の my-company.jp(会社HP)を同じサーバーで動かしたい場合などです。

コウ君

先生、それHTTPの時は簡単でしたよ!
<VirtualHost> ってやつを書いて、ドメインごとにフォルダを変えればいいんですよね?
SSLでも同じように書けば動くんじゃないんですか?

リナックス先生

ふふ、実はSSLの世界では、それが長い間「不可能」だったの。
通信の中身(どのドメインにアクセスしたいか)を見る前に、暗号化の鍵(証明書)を渡さなきゃいけないという「鶏と卵」の問題があったからよ。
でも安心して。今は「SNI(Server Name Indication)」という技術のおかげで、HTTPと同じように簡単に設定できるわ。
今回は、1つのIPアドレスで無限にHTTPSサイトを立ち上げる方法をマスターしましょう!

本記事では、AlmaLinux 9 (Apache 2.4) 環境において、複数のドメインに対してそれぞれ異なるSSL証明書を適用し、適切にアクセスを振り分ける「SSLバーチャルホスト」の構築手順を徹底解説します。

🔒 Apache SSL/TLS 完全攻略講座(バックナンバー)

現在地:【第5回】1つのIPで複数ドメイン!バーチャルホストでのSSL設定とSNIの仕組み


第1章:なぜ昔は「1IP=1証明書」だったのか?(SNIの仕組み)

設定を始める前に、なぜこの技術が必要なのか、仕組みを理解しておきましょう。
ここを知っておくと、トラブルシューティングの勘が鋭くなります。

SSLのジレンマ(鶏と卵)

HTTP(平文)の場合、ブラウザは「Hostヘッダー」でアクセスしたいドメイン名をサーバーに伝えます。
サーバーはそれを見て、「あ、A.comのページね」と判断してコンテンツを返します。

しかしHTTPSの場合、「暗号化通信の確立(SSLハンドシェイク)」が先に始まります。
サーバーは、暗号化を開始するために「証明書」を提示しなければなりませんが、まだ暗号化されていないため、クライアントが「どのドメイン(A.comかB.comか)」にアクセスしたいのか分かりません。

分からなければ、サーバーはとりあえず「デフォルトの証明書(A.com用)」を出すしかありません。
もしクライアントがB.comにアクセスしたかった場合、「証明書のドメイン名が違う(証明書エラー)」となって接続が切断されてしまうのです。

救世主「SNI (Server Name Indication)」

この問題を解決するために、TLSの拡張仕様としてSNIが生まれました。
これは、SSLハンドシェイクの最初の一歩(Client Hello)で、ブラウザが「私は今から〇〇というドメインと通信したいです!」と(平文で)宣言する仕組みです。

これにより、サーバー側は「〇〇ドメインですね、では〇〇用の証明書を出します」と正しい証明書を選んで提示できるようになりました。
現在、Apache 2.4系は標準でSNIに対応しており、特に追加の設定なしで利用可能です。


第2章:構成シナリオと事前準備

今回は、1台のAlmaLinuxサーバー(IP: 192.168.1.100)で、以下の2つのサイトをSSL化して公開するシナリオで進めます。

サイト名 ドメイン ドキュメントルート 証明書の種類
メインサイト www.example.com /var/www/html/www Let’s Encrypt
サブサイト blog.example.com /var/www/html/blog 自己署名(または別の証明書)

1. ディレクトリの作成

それぞれのコンテンツを置くディレクトリを作成します。

sudo mkdir -p /var/www/html/www
sudo mkdir -p /var/www/html/blog

# テスト用ファイルの作成
echo "<h1>Main Site</h1>" | sudo tee /var/www/html/www/index.html
echo "<h1>Blog Site</h1>" | sudo tee /var/www/html/blog/index.html

# 権限の調整
sudo chown -R apache:apache /var/www/html

2. 証明書の準備

それぞれのドメイン用の証明書と秘密鍵を用意しておいてください。
今回はパスを以下と仮定します。

  • www.example.com用:
    • /etc/pki/tls/certs/www.crt
    • /etc/pki/tls/private/www.key
  • blog.example.com用:
    • /etc/pki/tls/certs/blog.crt
    • /etc/pki/tls/private/blog.key

※Certbotを使う場合は、後述する自動設定でパスが変わりますが、まずは手動設定の基本を押さえましょう。


第3章:Apacheの設定(名前ベースバーチャルホスト)

設定ファイルは、管理しやすいようにドメインごとに分けるのがベストプラクティスです。
/etc/httpd/conf.d/ の下に vhost-ssl.conf というファイルを作ってまとめるか、個別に作ります。

設定ファイルの作成

sudo nano /etc/httpd/conf.d/vhost-ssl.conf

以下の内容を記述します。

# ------------------------------------------------
# 1つ目のサイト: www.example.com
# ------------------------------------------------
<VirtualHost *:443>
    ServerName www.example.com
    DocumentRoot /var/www/html/www

    # SSL設定
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/www.crt
    SSLCertificateKeyFile /etc/pki/tls/private/www.key
    # 中間証明書が必要な場合
    # SSLCertificateChainFile /etc/pki/tls/certs/www-chain.crt

    # ログ設定(ドメインごとに分けるのがコツ!)
    ErrorLog logs/www-error.log
    CustomLog logs/www-access.log combined
</VirtualHost>

# ------------------------------------------------
# 2つ目のサイト: blog.example.com
# ------------------------------------------------
<VirtualHost *:443>
    ServerName blog.example.com
    DocumentRoot /var/www/html/blog

    # SSL設定(別の証明書を指定)
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/blog.crt
    SSLCertificateKeyFile /etc/pki/tls/private/blog.key

    # ログ設定
    ErrorLog logs/blog-error.log
    CustomLog logs/blog-access.log combined
</VirtualHost>

⚠️ 重要:_default_ 設定との競合
デフォルトの /etc/httpd/conf.d/ssl.conf には、<VirtualHost _default_:443> という設定が入っています。
これは「どのServerNameにもマッチしなかった場合に使われる設定」ですが、これが存在すると、SNIがうまく機能しない場合があります。
自分が作成した vhost-ssl.conf を優先させるため、元の ssl.conf 内の VirtualHost ブロックはコメントアウトするか、ファイル名を変更(例: 00-ssl.conf)して読み込み順を制御することをお勧めします。

設定の反映

# 構文チェック
sudo apachectl configtest

# 再起動
sudo systemctl restart httpd

これで、ブラウザからそれぞれのドメインにアクセスしてみてください。
それぞれ正しい証明書が提示されれば成功です!


第4章:Certbotを使った自動設定(推奨)

手動設定は理解のためには重要ですが、実務では Certbot を使うのが圧倒的に楽で確実です。
Certbotは、Apacheのバーチャルホスト設定を読み取り、賢く証明書を発行・設定してくれます。

前提条件:HTTPのバーチャルホスト設定

Certbotを使うには、まずHTTP(80番ポート)の設定が済んでいることが必要です。
/etc/httpd/conf.d/vhost.conf などに以下のように書いておきます。

<VirtualHost *:80>
    ServerName www.example.com
    DocumentRoot /var/www/html/www
</VirtualHost>

<VirtualHost *:80>
    ServerName blog.example.com
    DocumentRoot /var/www/html/blog
</VirtualHost>

Certbotの実行

以下のコマンドを実行します。

sudo certbot --apache

すると、以下のようにドメインの選択肢が出ます。

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: www.example.com
2: blog.example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces... (Enter 'c' to cancel):

ここで 1,2 と入力すれば、両方のドメインに対して一気に証明書を取得し、Apacheの設定ファイル(vhost-le-ssl.conf など)を自動生成してくれます。
個別に取得したい場合は、コマンドを2回に分けて実行しても構いません。

1枚の証明書にまとめる(SANs)

Certbotで複数ドメインを選択すると、デフォルトでは1枚の証明書に複数のドメイン名(SANs: Subject Alternative Names)が記載されます。
管理が楽になりますが、「www.example.com」の証明書詳細を見ると「blog.example.com」も含まれていることがバレてしまいます。
関係のない顧客同士のサイトをホストする場合などは、個別にコマンドを実行して証明書を分けるべきです。

# 個別に取得する場合
sudo certbot --apache -d www.example.com
sudo certbot --apache -d blog.example.com

第5章:ログの分割と運用管理テクニック

複数のサイトを運営する場合、アクセスログが混ざってしまうと解析が困難になります。
第3章の設定例でも書きましたが、ログファイルは必ず分けましょう。

1. ログファイル名の工夫

ServerName をファイル名に含めると管理しやすくなります。

ErrorLog logs/${ServerName}-error.log
CustomLog logs/${ServerName}-access.log combined

※ただし、Apacheの設定ファイル内で変数を使うにはモジュール等の対応が必要な場合があるため、基本はベタ書き(www.example.com-access.log)が無難です。

2. ローテーション設定(logrotate)

ログファイルを分けるとファイル数が増えるため、ログローテーションの設定も確認が必要です。
/etc/logrotate.d/httpd は通常 /var/log/httpd/*log を対象にしているため、自動的に全てのログファイルがローテーションされます。
特別な設定は不要ですが、ファイル名を変な場所(/home/user/logs/など)に変えた場合は、logrotateの設定追加が必要です。


第6章:トラブルシューティング「意図しないサイトが表示される」

バーチャルホスト運用で最も多いトラブルが、「アクセスしたドメインと違うサイトが表示される」という現象です。

現象

まだ設定していないドメイン(例: unknown.com)でサーバーにアクセスした時や、IPアドレス直打ち(https://192.168.1.100)でアクセスした時に、なぜか www.example.com の内容が表示されてしまう。

原因:デフォルトバーチャルホスト

Apacheは、リクエストされたホスト名に一致する ServerName が見つからなかった場合、「一番最初に読み込まれたVirtualHost」を使用します。
ファイル名のアルファベット順(00-ssl.conf -> vhost-ssl.conf…)で決まります。

対策:ダミーの先頭ホストを作る

意図しないアクセスを拒否するために、先頭にダミーのVirtualHostを置くのが定石です。
/etc/httpd/conf.d/00-default-ssl.conf というファイルを作ります。

<VirtualHost *:443>
    ServerName default
    DocumentRoot /var/www/html/default
    
    # 自己署名証明書などを適当に設定しておく(SSLエラーにならないように)
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/localhost.crt
    SSLCertificateKeyFile /etc/pki/tls/private/localhost.key

    # 全て403 Forbiddenを返す
    <Location />
        Require all denied
    </Location>
</VirtualHost>

これを置いておけば、IP直打ちなどの不正なアクセスは全てこのダミーホストに吸い込まれ、正規のサイトは守られます。


まとめ:1サーバーで無限の可能性

お疲れ様でした!
これで、IPアドレスを追加契約することなく、好きなだけSSLサイトを増やせるようになりました。

今回の重要ポイント:

  • SNIのおかげで、1つのIPで複数のSSLサイトが運用可能。
  • 設定ファイルはドメインごとに <VirtualHost *:443> ブロックを作る。
  • Certbotを使えば、マルチドメイン設定も全自動。
  • デフォルトホスト(一番目の設定)の挙動に注意する。

さて、ここまででサーバー側の設定はかなり完璧に近づいてきました。
しかし、Webの世界には「証明書チェーン」という複雑な仕組みがあり、ここを理解していないと「PCでは見れるのにスマホで見れない」「Javaのプログラムから繋がらない」といった奇妙なトラブルに遭遇します。

次回、第6回は「『繋がらない』を解決!中間証明書チェーンとトラブルシューティング」です。
証明書の階層構造(ルート、中間、エンドエンティティ)を図解し、openssl コマンドを使ってチェーン切れを診断・修復するプロの技を伝授します。
お楽しみに!

▼ エンジニアとしてのキャリアを加速させる ▼

マルチドメインを試す
「VPS」で自分専用環境

おすすめVPSを見る

サーバー知識を年収に
「ITエンジニア転職」

転職エージェントを見る

コメント