発生している問題
SectigoやDigiCert、Let's Encryptなどのプロバイダーから、新しいSSL証明書をダウンロードしたばかりだとします。通常の手順に従い、ドメイン証明書と中間証明書ファイルを1つの.crtバンドルに結合しました。しかし、NginxやApacheをリロードしようとすると、サービスが停止してしまいます。
サービスは「active(起動中)」の緑色のステータスにならず、起動に失敗します。エラーログを確認したり設定テストを実行したりすると、次のようなOpenSSLのエラーが表示されます。
nginx: [emerg] SSL_CTX_use_Certificate("/etc/nginx/ssl/bundle.crt") failed
(SSL: error:140AB022:SSL routines:SSL_CTX_use_Certificate:diff orders of certificates)
原因
このエラーは、証明書ファイルの順序が正しくないことをOpenSSLが端的に指摘しています。Webサーバーは順序に厳格です。サーバーは証明書バンドルを上から順に読み込み、特定の階層構造を期待します。実際のドメイン証明書を見つける前に中間証明書が現れると、サーバーは処理を中断してしまいます。
Webサーバーを正しく動作させるには、バンドルファイルが以下の厳格な「リーフからルートへ(leaf-to-root)」の順序に従っている必要があります。
- **サーバー(リーフ)証明書:**特定のドメイン証明書(例:
example.com)。 - **中間証明書:**認証局(CA)から提供されるブリッジ証明書。
- **ルート証明書:**最上位のCA証明書(ほとんどのブラウザが既に保持しているため、通常は任意)。
多くの場合、このエラーはドメイン証明書をファイルの先頭ではなく、誤って末尾に追加してしまったことが原因で発生します。
解決策:証明書バンドルの順序変更
この問題を解決するには、証明書ブロックを手動で編集する必要があります。各ブロックは、-----BEGIN CERTIFICATE-----で始まり-----END CERTIFICATE-----で終わるエンコードされたテキストの塊です。
ステップ1:ファイル内容の確認
どのブロックがどれであるかを推測しないでください。OpenSSLを使用してbundle.crtファイルの中身を確認し、現在どの証明書が先頭にあるかを特定できます。
ファイル内の最初の証明書の情報を確認するには、次のコマンドを実行します:
openssl x509 -in bundle.crt -text -noout | grep -E 'Subject:|Issuer:'
出力のSubject行を確認してください。ドメイン(例:CN = example.com)が表示されていれば、最初のブロックは正しい状態です。しかし、SubjectにCN = Sectigo RSA Organization ValidationのようなCA名が表示されている場合は、それが原因です。中間証明書が間違った場所に配置されています。
ステップ2:順序の修正
nanoやvimなどのテキストエディタでバンドルファイルを開きます:
sudo nano /etc/nginx/ssl/bundle.crt
以下のパターンに従うようにブロックを並べ替えます。ENDタグとBEGINタグの間に余計なスペースや空行が入らないように注意してください:
-----BEGIN CERTIFICATE-----
(ドメイン証明書: example.com)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(中間証明書 1: 例 Sectigo RSA DV Bundle)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(中間証明書 2 - 提供されている場合)
-----END CERTIFICATE-----
ステップ3:新しい構造の検証
Webサーバーを再起動する前に、OpenSSLでファイルを検証します。このコマンドは、サーバーのロードプロセスをシミュレートします:
openssl x509 -in /etc/nginx/ssl/bundle.crt -noout -text
コマンドが「diff orders」エラーを出さずにドメインの技術詳細を返せば、証明書チェーンの修正は成功です。
変更の適用
Nginxの場合
Nginxは、結合されたファイルを指すためにssl_certificateディレクティブを使用します。サーバーブロックが以下のようになっていることを確認してください:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/bundle.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
}
nginx -tで構文エラーをチェックします。問題がなければ、サービスをリロードします:systemctl reload nginx。
Apacheの場合
Apache 2.4.8以降では、SSLCertificateFileディレクティブが新しく順序を整えたバンドルファイルを指すようにします。この1つのファイルで、ドメイン証明書と証明書チェーンの両方を処理します。
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/bundle.crt
SSLCertificateKeyFile /etc/apache2/ssl/example.com.key
</VirtualHost>
apachectl configtestを実行して、すべてが有効であることを確認します。Syntax OKと表示されたら、サービスを再起動します:systemctl restart apache2。
結果の確認
サーバーがオンラインに戻ったら、外部から証明書チェーンを検証します。ブラウザを使用することもできますが、openssl s_clientツールのほうがより詳細な情報を得られます:
openssl s_client -connect localhost:443 -showcerts
「Certificate chain」セクションを探します。ドメインがレベル0に、中間証明書がレベル1に表示されているはずです。この順序が確認できれば、「diff orders」エラーは正式に解消されたことになります。

