症状

nginxでHTTPS接続時に「この接続ではプライバシーが保護されません」「NET::ERR_CERT_AUTHORITY_INVALID」「SSL_ERROR_RX_RECORD_TOO_LONG」などのSSL証明書関連エラーが表示される。

結論:まずこれを確認

  1. 証明書の有効期限を確認する:echo | openssl s_client -connect localhost:443 2>/dev/null | openssl x509 -noout -dates
  2. nginxの設定で ssl_certificatessl_certificate_key のパスが正しいか確認する
  3. 証明書ファイルのパーミッションを確認する(nginxユーザーが読めるか)

トラブルシューティングフロー

    flowchart TD
    A[SSL証明書エラー発生] --> B{ブラウザのエラー種別は?}
    B -->|期限切れ系| C[証明書の有効期限を確認]
    B -->|信頼できない系| D[中間証明書を確認]
    B -->|接続エラー系| E[nginx設定を確認]
    C --> F{期限切れ?}
    F -->|Yes| G[証明書を更新]
    F -->|No| H[システム時刻を確認]
    D --> I{中間証明書あり?}
    I -->|No| J[中間証明書を結合]
    I -->|Yes| K[証明書チェーンを確認]
    E --> L{設定ファイルにエラー?}
    L -->|Yes| M[パス・構文を修正]
    L -->|No| N[パーミッションを確認]
  

よくある原因

  • 証明書の有効期限切れ - Let’s Encryptは90日、更新忘れが多い
  • 中間証明書の未設定 - サーバー証明書のみで中間証明書が結合されていない
  • 証明書ファイルパスの誤り - nginx設定内のパスが実際のファイル位置と異なる
  • 秘密鍵と証明書の不一致 - 異なる鍵ペアの証明書と秘密鍵を指定している
  • パーミッション不足 - nginxのワーカープロセスが証明書ファイルを読めない
  • ポート443でHTTP設定 - HTTPSサーバーブロックにSSL設定がない
  • サーバー名の不一致 - 証明書のCN/SANとアクセス先ドメインが異なる

確認手順

ステップ1: 証明書の有効期限を確認する

    # リモートから確認
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

# ローカルファイルを直接確認
openssl x509 -in /etc/nginx/ssl/server.crt -noout -dates
  

🔍 チェックポイント: notAfter が現在日時より未来であれば有効期限内

ステップ2: 証明書と秘密鍵の整合性を確認する

    # 証明書のモジュラス(ハッシュ)
openssl x509 -noout -modulus -in /etc/nginx/ssl/server.crt | openssl md5

# 秘密鍵のモジュラス(ハッシュ)
openssl rsa -noout -modulus -in /etc/nginx/ssl/server.key | openssl md5
  

🔍 チェックポイント: 両方の出力が一致すれば、証明書と秘密鍵はペアである

ステップ3: 中間証明書の設定を確認する

    # 証明書チェーンを確認
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null | grep -E "s:|i:"
  

🔍 チェックポイント: ルート認証局まで正しくチェーンがつながっている

ステップ4: nginx設定を確認する

    # 設定ファイルの構文チェック
nginx -t

# SSL関連の設定を抽出
grep -r "ssl_certificate" /etc/nginx/
  

🔍 チェックポイント: nginx -tsyntax is oktest is successful が表示される

ステップ5: 証明書ファイルのパーミッションを確認する

    # 証明書ファイルの権限
ls -la /etc/nginx/ssl/

# nginxの実行ユーザーを確認
ps aux | grep nginx | grep -v grep
  

🔍 チェックポイント: 証明書は644以上、秘密鍵は600でnginxユーザーが読める

ステップ6: サーバー名と証明書の一致を確認する

    # 証明書のCN(Common Name)とSAN(Subject Alternative Name)を確認
openssl x509 -in /etc/nginx/ssl/server.crt -noout -text | grep -A1 "Subject:"
openssl x509 -in /etc/nginx/ssl/server.crt -noout -text | grep -A1 "Subject Alternative Name"
  

🔍 チェックポイント: アクセスするドメイン名が証明書のCNまたはSANに含まれている

ステップ7: Let’s Encrypt自動更新の状態を確認する(該当する場合)

    # certbotの証明書一覧
certbot certificates

# 更新テスト(実際には更新しない)
certbot renew --dry-run
  

🔍 チェックポイント: dry-run が成功し、証明書の残り日数が表示される

NG行動(やってはいけないこと)

  • 秘密鍵のパーミッションを777にする - セキュリティリスク、秘密鍵は600が適切
  • エラーを無視してnginxを強制再起動する - 設定エラーの原因が不明なまま状態が悪化する
  • 本番環境で証明書ファイルを直接編集する - バックアップなしで作業すると復旧困難
  • 自己署名証明書を本番で使用する - ブラウザ警告が出続け、ユーザーが離脱する
  • 中間証明書なしでルート証明書を結合する - 一部ブラウザ・OSで検証に失敗する

よくある質問(FAQ)

Q1: Let’s Encryptの証明書が自動更新されない場合は?

A: certbot renew --dry-run でエラー内容を確認する。ポート80/443の疎通、webroot パスの設定、DNSレコードの確認が必要。cronジョブまたはsystemd timerの設定も確認する。

Q2: 中間証明書はどこで入手する?

A: 証明書発行元(CA)のWebサイトからダウンロードする。Let’s Encryptの場合は fullchain.pem を使用すると中間証明書が含まれている。

Q3: 複数ドメインを1つの証明書でカバーできる?

A: SAN(Subject Alternative Name)対応の証明書、またはワイルドカード証明書(*.example.com)を使用する。Let’s Encryptでは -d オプションで複数ドメインを指定可能。

関連するエラー・症状

解決しない場合

公式ドキュメント

確認すべきログファイル

    # nginxエラーログ
/var/log/nginx/error.log

# Let's Encryptログ
/var/log/letsencrypt/letsencrypt.log
  

次に調べるキーワード

  • nginx ssl handshake failed
  • certificate verify failed
  • SSL routines:ssl3_get_server_certificate
  • certbot renewal failed