Labee Dev Toolbox
技術ノートガイド用語解説
無料で試す
  1. ホーム
  2. / 用語解説
  3. / SNI(Server Name Indication)
SSL

SNI(Server Name Indication)

2025年12月18日 更新

概要

SNI(Server Name Indication) は、TLS ハンドシェイクの ClientHello メッセージにホスト名を含めることで、1 つの IP アドレスで複数のドメインの証明書を使い分けられるようにする TLS 拡張です。RFC 6066(2011 年)で定義されています。

SNI が登場する前、TLS では 1 つの IP アドレスに 1 枚の証明書しか対応できませんでした。複数のドメインを同一サーバーでホストする場合、ドメインごとに異なる IP アドレスを割り当てる必要があり、IP アドレスの枯渇問題と設定コストの増大を招いていました。

HTTP/1.1 では Host ヘッダーによってバーチャルホストを実現しています。しかし TLS ハンドシェイクは HTTP より先に行われるため、証明書を選択する時点ではまだ Host ヘッダーを読めません。SNI はこのギャップを解消します。クライアントが接続先のホスト名を TLS ハンドシェイクの最初の段階で通知することで、サーバーは適切な証明書を選択してハンドシェイクを続けられます。

仕組み

SNI は TLS ハンドシェイクの最初のメッセージでホスト名を通知し、サーバーが適切な証明書を選択できるようにします。

TLS ハンドシェイクでの SNI の役割

TLS ハンドシェイクにおける SNI の処理順序は次のとおりです。

  1. クライアントが ClientHello を送る。このメッセージの server_name 拡張フィールドに接続先のホスト名(例: example.com)が含まれる
  2. サーバーは server_name を参照して、対応する証明書と秘密鍵を選択する
  3. サーバーが ServerHello と選択した証明書を返す
  4. クライアントは証明書を検証し、ハンドシェイクを完了する

SNI がない場合、サーバーはデフォルト証明書を返すか、エラーを返します。デフォルト証明書が別のドメインのものであればホスト名検証に失敗し、ブラウザーは接続を拒否します。

サーバー側の設定

Nginx では server_name ディレクティブで SNI の照合先を設定します。複数のサーバーブロックに同じ IP と同じポートを指定すると、Nginx はクライアントから受け取った SNI 値に基づいて適切なブロックを選択します。

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}

server {
    listen 443 ssl;
    server_name api.example.com;
    ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
}

上記の 2 つのサーバーブロックは同一 IP の 443 ポートを共有し、SNI によってどちらの証明書を使うか決定します。

確認方法

openssl で接続時に SNI が正しく機能しているか確認するには次のコマンドを使います。

# SNI を明示的に指定して接続(-servername オプション)
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer
subject=CN = example.com
issuer=C = US, O = Let's Encrypt, CN = R10

-servername オプションが SNI に相当します。返ってきた証明書の subject が期待するドメインと一致していれば SNI が正しく機能しています。

SNI を指定せずに接続して何が返ってくるか確認するには次のように実行します。

# SNI なしで接続(デフォルト証明書が返る)
openssl s_client -connect 203.0.113.1:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -subject

外部の視点からも確認したい場合は、Labee Dev Toolbox の SSL Cert API を使うと、外部の視点から見た結果を取得できます。

curl "https://labee.dev/api/ssl-cert?hostname=example.com"
{
  "success": true,
  "data": {
    "hostname": "example.com",
    "port": 443,
    "reachable": true,
    "status": 200
  },
  "error": null,
  "meta": { "responseTime": 123 }
}

data.reachable が true であれば SNI を含む TLS ハンドシェイクが正常に完了し、HTTPS 接続が確立されています。

よくある問題

SNI に関するトラブルは、IP 直接接続時のホスト名不一致やデフォルトサーバーの証明書選択に起因するものが中心です。

SNI を使わず IP アドレスで直接接続

curl https://203.0.113.1/ のように IP アドレスで接続すると、SNI が指定されないためデフォルト証明書が返ります。証明書のホスト名がアクセス先の IP アドレスと一致しないため、ホスト名検証に失敗します。IP アドレスでのアクセスが必要な場合は、-k フラグで検証を無効化するかホスト名を -H Host: ヘッダーで指定しますが、本番環境では避けます。

Nginx のデフォルトサーバーが意図しない証明書を返す

複数のサーバーブロックがある場合、SNI に一致するものがなければ Nginx は default_server フラグのついたブロックの証明書を返します。default_server を明示的に設定していない場合は最初に定義されたサーバーブロックがデフォルトになります。意図しない証明書が返ってきてホスト名検証が失敗するケースはこれが原因のことが多いです。

ワイルドカード証明書と SNI の組み合わせ

*.example.com のワイルドカード証明書は第 1 レベルのサブドメイン(api.example.com、www.example.com)をカバーしますが、a.b.example.com のような 2 階層以上の深さのサブドメインはカバーしません。SNI でホスト名を正しく通知できても、証明書のホスト名検証で失敗します。2 階層以上のサブドメインには SAN 証明書を使います。

HAProxy や ALB でのバックエンドへの SNI 転送

L7 ロードバランサーを経由する構成で、バックエンドにも SNI が必要な場合は設定が必要です。HAProxy では ssl verify required sni str(example.com) を指定し、AWS ALB では対象バックエンドの SNI 設定を有効化します。設定が漏れると、バックエンドサーバーがデフォルト証明書を返し、ALB がホスト名検証に失敗します。

古いクライアントとの互換性

SNI は TLS の拡張であるため、SNI をサポートしないクライアントはホスト名を含まない ClientHello を送ります。この場合、サーバーはどのドメインへのアクセスか判断できないため、デフォルト証明書(最初に定義されたサーバーブロックの証明書)を返します。

SNI のブラウザー対応は 2006 年頃から始まりました。Firefox 2.0、Internet Explorer 7 がこの世代です。現在の一般的なブラウザーやモバイル OS はすべて SNI に対応しています。

問題が起きるのは次のようなケースです。

  • Windows XP の Internet Explorer 6 以前(2006 年以前のブラウザー)
  • Python 2 系の urllib2(2012 年以前のバージョン)
  • OpenSSL 0.9.8 以前(2005 年以前のバージョン)
  • 一部の古い Java アプリケーション(JDK 1.6 未満)

現代的なシステムでは SNI の非対応クライアントを考慮する機会はほぼありません。ただし組み込みデバイス、古いネットワーク機器、レガシーシステムとの連携では注意が必要な場合があります。

ECH(Encrypted Client Hello)

SNI の課題として、ClientHello のホスト名が平文で送信されるため、通信経路上の第三者(ISP、ファイアウォール、ネットワーク機器)がアクセス先のホスト名を傍受できます。HTTPS を使っていても SNI だけで通信先のドメインが把握される点はプライバシー上の問題です。

この問題を解決するために開発されたのが ECH(Encrypted Client Hello) です。RFC 9849 で標準化されており、ClientHello 全体を暗号化します。ECH を使うと、ネットワーク上で見えるのはアウターの SNI(通常は CDN のドメイン)のみになります。Chrome 117 以降と Firefox 119 以降でデフォルト有効化されており、DNS レコード(HTTPS リソースレコード)でサーバーの ECH 公開鍵を配布するインフラが必要です。

実際のドメインで確認してみる

登録不要、無料です。ドメイン名を入れるだけで外部からの見え方を確認できます。

無料で試す

関連用語

SSL

SSL/TLS 証明書

ウェブサイトの通信を暗号化し、サーバーの身元を証明するデジタル証明書。HTTPS 配信の前提条件。

SSL

HSTS(HTTP Strict Transport Security)

ブラウザーに HTTPS 接続を強制するセキュリティポリシー。HTTP へのアクセスを自動的に HTTPS へアップグレードします。

SSL

証明書透明性(Certificate Transparency)

CA が発行した証明書をパブリックログに記録し、不正発行を検知可能にする仕組み。Chrome は CT ログ未登録の証明書を拒否する。

コンテンツ 技術ノート ガイド 用語解説
ツール ツール一覧 API Reference
Labee 日本語トップ Labee LLC
© 2026 Labee LLC . All rights reserved.
ホーム ブログ ガイド 用語集