HTTPS サーバーの設定

HTTPS サーバーの最適化
SSL 証明書チェーン
単一の HTTP/HTTPS サーバー
名前ベースの HTTPS サーバー
     複数の名前を持つ SSL 証明書
     サーバー名表示 (SNI)
互換性

HTTPS サーバーを設定するには、server ブロック内の リスニングソケットssl パラメーターを有効にし、サーバー証明書秘密鍵 ファイルの場所を指定する必要があります。

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

サーバー証明書は公開エンティティです。サーバーに接続するすべてのクライアントに送信されます。秘密鍵は安全なエンティティであり、アクセス制限のあるファイルに保存する必要がありますが、nginx のマスタープロセスが読み取れる必要があります。秘密鍵は、証明書と同じファイルに保存することもできます。

    ssl_certificate     www.example.com.cert;
    ssl_certificate_key www.example.com.cert;

この場合、ファイルのアクセス権も制限する必要があります。証明書と鍵は 1 つのファイルに保存されますが、クライアントに送信されるのは証明書のみです。

ssl_protocols および ssl_ciphers ディレクティブを使用して、SSL/TLS の強力なバージョンと暗号のみを含むように接続を制限できます。デフォルトでは、nginx は「ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3」および「ssl_ciphers HIGH:!aNULL:!MD5」を使用するため、明示的に設定する必要は通常ありません。これらのディレクティブのデフォルト値は、何度か変更されていることに注意してください。

HTTPS サーバーの最適化

SSL 操作は、追加の CPU リソースを消費します。マルチプロセッサシステムでは、利用可能な CPU コアの数以上の ワーカープロセス を実行する必要があります。最も CPU を集中的に使用する操作は、SSL ハンドシェイクです。クライアントごとのこれらの操作の数を最小限に抑えるには、2 つの方法があります。1 つ目は、キープアライブ 接続を有効にして、1 つの接続で複数のリクエストを送信することです。2 つ目は、SSL セッションパラメータを再利用して、並列および後続の接続の SSL ハンドシェイクを回避することです。セッションは、ワーカー間で共有される SSL セッションキャッシュに保存され、ssl_session_cache ディレクティブによって設定されます。1 メガバイトのキャッシュには、約 4000 セッションが含まれています。デフォルトのキャッシュタイムアウトは 5 分です。ssl_session_timeout ディレクティブを使用して、これを増やすことができます。10 メガバイトの共有セッションキャッシュを備えたマルチコアシステムに最適化されたサンプル設定を以下に示します。

worker_processes auto;

http {
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;

    server {
        listen              443 ssl;
        server_name         www.example.com;
        keepalive_timeout   70;

        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ...

SSL 証明書チェーン

一部のブラウザは、よく知られた認証局によって署名された証明書について警告を表示することがありますが、他のブラウザは問題なく証明書を受け入れる場合があります。これは、発行元が、特定のブラウザに配布されているよく知られた信頼できる認証局の証明書ベースに存在しない中間証明書を使用してサーバー証明書に署名しているために発生します。この場合、認証局は、署名されたサーバー証明書に連結する必要がある chained 証明書のバンドルを提供します。結合されたファイルでは、サーバー証明書は chained 証明書の前に配置する必要があります。

$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt

結果のファイルは、ssl_certificate ディレクティブで使用してください.

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

サーバー証明書とバンドルが間違った順序で連結されている場合、nginx は起動に失敗し、次のエラーメッセージが表示されます.

SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
   (SSL: error:0B080074:x509 certificate routines:
    X509_check_private_key:key values mismatch)

これは、nginx がサーバー証明書ではなく、バンドルの最初の証明書で秘密鍵を使用しようとしたためです。

ブラウザは通常、受信した中間証明書と、信頼できる認証局によって署名された中間証明書を保存するため、アクティブに使用されているブラウザには必要な中間証明書が既にあり、chained バンドルなしで送信された証明書について警告が表示されない場合があります。サーバーが完全な証明書チェーンを送信するようにするには、たとえば、openssl コマンドラインユーティリティを使用できます.

$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/CN=www.GoDaddy.com
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=ValiCert, Inc.
     /OU=ValiCert Class 2 Policy Validation Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.com
...

SNI を使用して構成をテストする場合、openssl はデフォルトでは SNI を使用しないため、-servername オプションを指定することが重要です。

この例では、www.GoDaddy.com サーバー証明書 #0 のサブジェクト(「s」)は、発行者(「i」)によって署名されており、発行者自体は証明書 #1 のサブジェクトであり、発行者によって署名されています。証明書 #2 のサブジェクトであり、ブラウザの組み込み証明書ベースに証明書が保存されているよく知られた発行者 *ValiCert, Inc.* によって署名されています(ジャックが建てた家にあります)。

証明書バンドルが追加されていない場合は、サーバー証明書 #0 のみが表示されます。

単一の HTTP/HTTPS サーバー

HTTP リクエストと HTTPS リクエストの両方を処理する単一サーバーを構成することができます。

server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

0.7.14 より前では、上記のように、個々のリスニングソケットに対して SSL を選択的に有効にすることができませんでした。ssl ディレクティブを使用してサーバー全体に対してのみ SSL を有効にできたため、単一の HTTP/HTTPS サーバーを設定できませんでした。listen ディレクティブの ssl パラメータは、この問題を解決するために追加されました。したがって、最新バージョンでは ssl ディレクティブの使用はお勧めしません。

名前ベースの HTTPS サーバー

単一の IP アドレスでリッスンしている 2 つ以上の HTTPS サーバーを設定する場合、よくある問題が発生します。

server {
    listen          443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

この構成では、ブラウザは、リクエストされたサーバー名に関係なく、デフォルトサーバーの証明書、つまり www.example.com を受信します。これは、SSL プロトコルの動作が原因です。SSL 接続はブラウザが HTTP リクエストを送信する前に確立され、nginx はリクエストされたサーバーの名前を知りません。したがって、デフォルトサーバーの証明書のみを提供できます.

この問題を解決するための最も古く、最も堅牢な方法は、すべての HTTPS サーバーに個別の IP アドレスを割り当てることです.

server {
    listen          192.168.1.1:443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

複数の名前を持つ SSL 証明書

複数の HTTPS サーバー間で単一の IP アドレスを共有できる他の方法があります。ただし、それらはすべて欠点があります。1 つの方法は、SubjectAltName 証明書フィールドに複数の名前(たとえば、`www.example.com` と `www.example.org`)を持つ証明書を使用することです。ただし、SubjectAltName フィールドの長さには制限があります.

もう 1 つの方法は、ワイルドカード名(たとえば、`*.example.org`)の証明書を使用することです。ワイルドカード証明書は、指定されたドメインのすべてのサブドメインを保護しますが、1 つのレベルのみです。この証明書は `www.example.org` に一致しますが、`example.org` と `www.sub.example.org` には一致しません。これら 2 つの方法を組み合わせることもできます。証明書には、SubjectAltName フィールドに正確な名前とワイルドカード名を含めることができます(たとえば、`example.org` と `*.example.org`)。

すべてサーバーで単一のメモリコピーを継承するには、設定の *http* レベルに複数の名前を持つ証明書ファイルとその秘密鍵ファイルを配置することをお勧めします.

ssl_certificate     common.crt;
ssl_certificate_key common.key;

server {
    listen          443 ssl;
    server_name     www.example.com;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ...
}

サーバー名表示 (SNI)

単一の IP アドレスで複数の HTTPS サーバーを実行するためのより一般的なソリューションは、TLS Server Name Indication extension (SNI, RFC 6066) です。これにより、ブラウザは SSL ハンドシェイク中にリクエストされたサーバー名を渡すことができるため、サーバーは接続に使用する必要がある証明書を知ることができます。SNI は現在、ほとんどの最新のブラウザでサポートされていますが、古いクライアントや特別なクライアントでは使用されない場合があります.

SNI ではドメイン名のみを渡すことができますが、リクエストにリテラル IP アドレスが含まれている場合、一部のブラウザはサーバーの IP アドレスを誤って名前として渡す可能性があります。これに頼るべきではありません.

nginx で SNI を使用するには、nginx バイナリがビルドされた OpenSSL ライブラリと、実行時に動的にリンクされているライブラリの両方で SNI がサポートされている必要があります。OpenSSL は、設定オプション“--enable-tlsext” でビルドされた場合、バージョン 0.9.8f 以降で SNI をサポートしています。OpenSSL 0.9.8j 以降、このオプションはデフォルトで有効になっています。nginx が SNI サポートでビルドされた場合、nginx は「-V」スイッチで実行するとこれを表示します。

$ nginx -V
...
TLS SNI support enabled
...

ただし、SNI 対応の nginx が SNI サポートのない OpenSSL ライブラリに動的にリンクされている場合、nginx は警告を表示します.

nginx was built with SNI support, however, now it is linked
dynamically to an OpenSSL library which has no tlsext support,
therefore SNI is not available

互換性

Igor Sysoev 著
Brian Mercer 編集