Certbotで証明書を取ってHTTPS化はできた── だが「なぜ一部の環境だけ証明書エラーになるのか」「中間証明書とは何なのか」を説明できるだろうか.SSL/TLSの裏側を理解していないと,いざという証明書トラブルで手も足も出ない.

HTTPSは今やWebの大前提だが,その下で動くTLSはハンドシェイク・証明書チェーン・失効確認・暗号交渉という精密な仕組みでできている.ここを理解すれば,証明書トラブルの原因が手に取るように分かる.

この記事は,VPSでHTTPSサイトを運用する個人開発者,証明書エラーの原因を根本から理解したいエンジニアに向けている.仕組みの解説と,opensslを使った実践的なデバッグの両方を扱う.

読み終えたとき,あなたは証明書チェーンを読み解き,「一部環境だけエラー」の原因を特定し,暗号設定を適切に保てるようになっている.

なぜ運用者がTLSの中身を知るべきか

証明書トラブルは,「特定のブラウザ・古い端末・APIクライアントだけエラー」という形で現れることが多い.自分の環境では正常に見えるため,仕組みを知らないと原因にたどり着けない.

その代表が中間証明書の欠落だ.モダンブラウザは中間証明書を補完できることがあるが,補完しないクライアントではエラーになる.「自分のChromeでは見えるのに,あるユーザーだけ繋がらない」の典型原因がこれだ.

また古い暗号スイートやTLSバージョンを残すと,セキュリティ診断で警告が出たり,要件を満たせなかったりする.逆に絞りすぎると古いクライアントを切り捨てる.適切なバランスを取るには中身の理解が要る.

TLSの仕組みを知ることは,「動いている/いない」を超えて「なぜそうなるか」を説明できる運用者になることだ.

TLSハンドシェイクの流れ ― 何が起きているか

ブラウザがHTTPSサイトに繋ぐとき,通信の前にTLSハンドシェイクが行われる.大まかには,(1)使う暗号方式の交渉 (2)サーバー証明書の提示と検証 (3)暗号化に使う鍵の共有という流れだ.

このうち運用者が最も関わるのが(2)の証明書の提示と検証だ.サーバーは自分の証明書を提示し,クライアントはそれが信頼できるかを検証する.この検証で証明書チェーンが決定的な役割を果たす.

証明書チェーン ― ルート・中間・サーバー証明書

証明書は単独では信頼されない.「信頼の連鎖(チェーン)」でルート認証局まで遡れて初めて信頼される.この階層構造を理解することが,証明書トラブル解決の鍵だ.

証明書役割どこにあるか
ルート証明書信頼の起点OS/ブラウザに最初から入っている
中間証明書ルートとサーバーを繋ぐサーバーが提示する必要がある
サーバー証明書あなたのドメインの証明書サーバーが提示

クライアントは,サーバー証明書 → 中間証明書 → ルート証明書と遡って検証する.ルートはOS/ブラウザに内蔵されているが,中間証明書はサーバーが一緒に送らなければならない.ここが事故の温床だ.

定番事故 ― 中間証明書の欠落

最も多い証明書トラブルが,中間証明書を送っていない(チェーンが不完全)ことだ.モダンブラウザは欠けた中間証明書を補完できる場合があるが,補完しないクライアント(一部のAPIクライアント・古い端末)ではエラーになる.

「ブラウザでは見えるのに,curlやアプリからのアクセスだけ失敗する」── これはチェーン不完全の典型症状だ.Certbotで取得したfullchain.pem(サーバー証明書+中間証明書)を使えば,この問題は起きない.

チェーンが完全か確認する

# 提示されている証明書チェーンを確認
openssl s_client -connect example.com:443 -servername example.com -showcerts
# チェーン検証(完全ならVerify return code: 0 (ok))
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep -i "verify"

Verify return code: 0 (ok)と出ればチェーンは完全だ.エラーが出る場合,Nginxのssl_certificatefullchain(中間込み)を指定しているかを確認する.証明書単体ではなくチェーン込みを指すのが鉄則だ.

失効とOCSP ― 証明書を「無効化」する仕組み

証明書には有効期限とは別に,「途中で無効化する(失効)」仕組みがある.秘密鍵が漏れた場合などに,期限前でも証明書を無効にできる.この失効状態を確認する仕組みがOCSPだ.

クライアントは証明書が失効していないかをOCSPで問い合わせるが,これには遅延やプライバシーの問題がある.そこでOCSP Stapling── サーバーがあらかじめ失効情報を取得して証明書と一緒に提示する仕組み── が使われる.

OCSP Staplingの有効化(Nginx)

ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

OCSP Staplingを有効にすると,クライアントの失効確認が速くなり,プライバシーも守られる.設定は数行で,TLSハンドシェイクの体感速度にも寄与する.有効化後はopenssl s_client ... -statusでStaplingが効いているか確認できる.

暗号スイートとTLSバージョン ― 強度と互換のバランス

TLSでは,使用する暗号スイート(暗号アルゴリズムの組み合わせ)とTLSバージョンを交渉する.古いものを残すと脆弱性のリスク,絞りすぎると古いクライアントを切り捨てる.適切なバランスが要る.

TLS1.2/1.3のみ・推奨スイート(Nginx)

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:
            ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;

現代の推奨はTLS1.2とTLS1.3のみを有効にし,旧来のSSLv3/TLS1.0/1.1は無効化することだ.暗号スイートは前方秘匿性(ECDHE)のあるものを選ぶ.設定に迷ったら,モダンな構成例を生成してくれるツール(Mozilla SSL Configuration Generator等)を参考にするとよい.

TLS1.3の利点

TLS1.3はハンドシェイクが高速化(往復回数の削減)され,安全でない古い暗号方式が排除されている.有効にしておくだけで速度と安全性の両方が向上するため,対応環境では必ず有効にしたい.

セキュリティヘッダ ― HSTSで「常にHTTPS」を強制する

TLSの設定と併せて入れたいのがHSTS(HTTP Strict Transport Security)だ.これは「このサイトには今後必ずHTTPSで接続せよ」とブラウザに指示するヘッダで,HTTPへのダウングレード攻撃を防ぐ.

HSTSヘッダ(Nginx)

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

max-ageでHTTPS強制の期間を指定する.一度設定すると期間中はHTTPアクセスが拒否されるため,HTTPSが完全に安定してから入れること.サブドメインも含めるならincludeSubDomainsを付ける.これでHTTPSの守りが一段固くなる.

opensslでデバッグする ― 証明書の中身を読む

証明書トラブルの調査にはopensslが最強の武器だ.有効期限・発行者・チェーン・対象ドメインをコマンドで確認できる.

証明書デバッグの定番コマンド

# サーバーが提示する証明書の概要
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates
# ローカルの証明書ファイルの中身
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -text
# 有効期限だけ素早く確認
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate

-subject(対象ドメイン)・-issuer(発行者)・-dates(有効期間)を押さえれば,大半のトラブルは切り分けられる.「ドメイン名が証明書と一致しない」「期限切れ」「発行者が信頼されない」── 症状から原因へ一直線にたどり着ける.

補論:TLS設定の試行錯誤は「戻せるVPS」で安全に

TLS設定は,一つ間違えるとサイト全体がHTTPSで繋がらなくなる.暗号スイートの指定ミス,HSTSの過剰設定,チェーンの不備── どれも全ユーザーに影響する.だからこそ「失敗したら即戻せる」環境が重要だ.

高速NVMe・50種類以上のOSテンプレートに対応した国内VPS─シン・VPS─ はスナップショットを備え,NVMe SSDでNginxのリロードも軽快なため,TLS設定を大胆に試して,問題があれば設定前へ巻き戻す運用がしやすい.Certbotでの証明書取得・更新もスムーズで,本記事の暗号設定やOCSP Staplingを安心して適用できる.

HTTPSは独自ドメインがあって初めて意味を持つ.取り扱い400種類以上のドメイン取得サービス─ムームードメイン─ で取得したドメインに対し,完全なチェーン・TLS1.2/1.3・HSTSを設定すれば,どのクライアントからも安全に繋がる「正しいHTTPS」が完成する.

よくある質問(FAQ)

Q1.中間証明書とは何で、なぜ重要?

ルート認証局とサーバー証明書を繋ぐ証明書だ.サーバーが中間証明書を一緒に送らないと,補完しないクライアントで検証が失敗する.Certbotのfullchain.pem(中間込み)を使えば確実だ.

Q2.「ブラウザでは見えるのにcurlで失敗」する

証明書チェーンの不完全(中間証明書の欠落)が典型原因だ.ブラウザは補完できても,curlやAPIクライアントは補完しないことがある.openssl s_client -showcertsでチェーンを確認し,fullchainを指定する.

Q3.TLSのバージョンはどれを有効にすべき?

TLS1.2とTLS1.3のみが現代の推奨だ.SSLv3・TLS1.0/1.1は脆弱性があり無効化する.TLS1.3は速度と安全性が向上するので必ず有効にしたい.

Q4.OCSP Staplingは必須?

必須ではないが,失効確認が速くなり,プライバシーも守られるため有効化を推奨する.Nginxなら数行で設定でき,ハンドシェイクの体感速度にも寄与する.

Q5.HSTSを入れるときの注意は?

HTTPSが完全に安定してから入れること.一度設定すると期間中はHTTPアクセスが拒否されるため,HTTPSに問題があると復旧が面倒になる.まず短いmax-ageで試すのも手だ.

Q6.証明書の有効期限を確認したい

echo | openssl s_client -connect ドメイン:443 2>/dev/null | openssl x509 -noout -enddateで即確認できる.Certbotの自動更新が効いていれば基本は失効しないが,たまに確認する習慣は安心だ.

まとめ ― TLSの中身を知れば証明書は怖くない

SSL/TLSは,ハンドシェイク・証明書チェーン・失効確認・暗号交渉という精密な仕組みでできている.中でも証明書チェーン(特に中間証明書)を理解すれば,証明書トラブルの大半は自力で解決できる.

今日やるべきことは,openssl s_clientで自分のサイトのチェーンが完全(Verify return code: 0)か確認すること.そしてTLS1.2/1.3のみ・HSTSの設定を見直す.

「動いている」を「なぜ動くか説明できる」に変えること.それがTLSを深掘りする価値だ.戻せるVPSがあれば,暗号設定も恐れず最適化できる.