OCSP Stapling失敗を修正: OCSPレスポンス期限切れ / ssl_stapling unauthorized (Nginx & Apache)

intermediate🔒 SSL/TLS2026-03-23| Nginx 1.14以降、Apache 2.4以降、Ubuntu 20.04/22.04、Debian 11/12、CentOS 7/8、Let's Encrypt / 商用SSL証明書

Error Message

OCSP response has expired — ssl_stapling: OCSP response not successful (6: unauthorized)
#ssl#ocsp#stapling#nginx#apache

何が起きているか

TLSハンドシェイクの際、サーバーはあらかじめ取得したOCSPレスポンスをクライアントに送信しようとします——これがステープリングです。問題は、キャッシュされたレスポンスが期限切れになっているか、サーバーが新しいレスポンスを取得しようとした際にOCSPレスポンダーがエラーを返した場合です。クライアントは接続を完全に拒否するか、自分でOCSPステータスを取得するフォールバック処理を行い、レイテンシが増加します。

このエラーに関連する2つのログ行:

ssl_stapling: OCSP response not successful (6: unauthorized)
OCSP response has expired

エラーコード 6: unauthorized は、OCSPレスポンダーがリクエストを拒否したことを意味します。これは通常、3つの理由のいずれかで発生します:リクエストが不正な形式だった、サーバーが誤ったCAエンドポイントに問い合わせた、または証明書のAIA(Authority Information Access)拡張がサーバーから到達できないレスポンダーを指している場合です。

簡易診断

OpenSSLがインストールされた任意のマシンから以下を実行して、クライアントが実際に受け取る内容を確認します:

# クライアント側からOCSPステープリングをテスト
openssl s_client -connect yourdomain.com:443 -status 2>/dev/null | grep -A 10 'OCSP response'

正常なステープルはこのように表示されます:

OCSP Response Status: successful (0x0)
Cert Status: good

ステープリングが壊れている場合は no response sent または unauthorized が表示されます。次にログを確認します:

# Nginx
tail -n 100 /var/log/nginx/error.log | grep -i ocsp

# Apache
tail -n 100 /var/log/apache2/error.log | grep -i ocsp

修正1:古いOCSPキャッシュをクリアする

NginxはOCSPレスポンスをディスクではなくメモリにキャッシュします。キャッシュされたレスポンスが期限切れになり、サーバーが更新に失敗すると、すべての新しいTLSハンドシェイクでこのエラーが発生します。リロードするとメモリ内キャッシュがクリアされ、次のリクエスト時に新しいレスポンスが強制的に取得されます:

sudo nginx -t && sudo systemctl reload nginx

Apacheの場合:

sudo apachectl configtest && sudo systemctl reload apache2

リロード後にエラーが消えても24〜48時間以内に再発する場合、キャッシュが根本的な原因ではありません——サーバーがOCSPレスポンダーに到達できず、事前に更新できていない状態です。修正2に進んでください。

修正2:OCSPレスポンダーへの接続を確認する

証明書から直接OCSP URLを取得します:

openssl x509 -in /path/to/your/cert.pem -noout -text | grep -A 3 'Authority Information'

Let's Encrypt証明書の出力例:

Authority Information Access:
    OCSP - URI:http://r10.o.lencr.org
    CA Issuers - URI:http://r10.i.lencr.org/

サーバーから到達可能かテストします:

curl -v http://r10.o.lencr.org

タイムアウトする場合、OCSPレスポンダーがネットワークレベルでブロックされています。OCSPはポート80の平文HTTPで動作します——多くのファイアウォールルールでは、Webサーバー自身からのアウトバウンドHTTPの許可が忘れられています。開放してください:

# iptables
sudo iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT

# ufw
sudo ufw allow out 80/tcp

企業プロキシの背後にある場合は、NginxまたはApacheを起動する前に環境変数 http_proxy を設定するか、CAに到達できる resolver を使用してください(修正4を参照)。

修正3:証明書チェーンが完全であることを確認する

ほとんどの場合、ssl_stapling: OCSP response not successful (6: unauthorized) は中間証明書の欠落が原因です。OCSPステープリングには完全なチェーンが必要です——サーバーはステープルされたレスポンスをクライアントに渡す前に検証するために、チェーン全体が必要です。

Nginxの場合

ssl_certificate にはドメイン証明書だけでなく、フルチェーンファイルを指定します。さらに ssl_trusted_certificate を追加します——これがないと、NginxはCAから受け取ったOCSPレスポンスを検証できません:

server {
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;  # 中間証明書を含む
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;  # ステープリングに必須

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

Apacheの場合

<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/yourdomain.com/chain.pem

    SSLUseStapling on
</VirtualHost>

# VirtualHostブロックの外、メイン設定またはssl.confに記述:
SSLStaplingCache shmcb:/tmp/stapling_cache(128000)

設定変更後はリロードします:

sudo nginx -t && sudo systemctl reload nginx
# または
sudo apachectl configtest && sudo systemctl reload apache2

修正4:NginxにDNSリゾルバーを追加する

Nginxはレスポンダーのホスト名を解決できない場合、OCSPレスポンスをステープルできません。resolverディレクティブがないと、エラーも出ずにステープルも行われないサイレントな失敗が発生します。server ブロックだけでなく、http ブロックに追加します:

http {
    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 10s;
    # ... 残りの設定
}

追加後にNginxをリロードします。resolver_timeout の10sは保守的な値です——高速なネットワークでは通常5sで十分です。

修正5:cronジョブでOCSPレスポンスを事前取得する

レスポンダーには到達できるが、証明書更新のタイミングでギャップが生じる場合は、スケジュールに従ってレスポンスを事前取得し、Nginxが常に新鮮なステープルを持てるようにします:

#!/bin/bash
# /usr/local/bin/refresh-ocsp.sh

CERT=/etc/letsencrypt/live/yourdomain.com/cert.pem
CHAIN=/etc/letsencrypt/live/yourdomain.com/chain.pem
OCSP_URL=$(openssl x509 -in $CERT -noout -ocsp_uri)

openssl ocsp \
  -issuer $CHAIN \
  -cert $CERT \
  -url $OCSP_URL \
  -respout /tmp/ocsp.der \
  -no_nonce 2>&1

echo "OCSP refresh done at $(date)"

12時間ごとにスケジュールします——Let's EncryptのOCSPレスポンスは7日間有効ですが、頻繁に更新することで有効期限に十分な余裕を持てます:

0 */12 * * * /usr/local/bin/refresh-ocsp.sh >> /var/log/ocsp-refresh.log 2>&1

修正の確認

リロード後、OpenSSLチェックを再実行します:

openssl s_client -connect yourdomain.com:443 -status 2>/dev/null | grep -A 10 'OCSP Response'

以下のように表示されることを確認します:

OCSP Response Status: successful (0x0)
This Update: Mar 23 10:00:00 2026 GMT
Next Update: Mar 30 10:00:00 2026 GMT
Cert Status: good

SSL LabsでもOCSPステープリングのステータスを確認できます——ドメインを送信し、結果に OCSP Stapling: Yes が表示されることを確認してください。

リロード直後もNginxのログにエラーが表示される場合は、60〜90秒待ってください。NginxはリロードHat後の最初のリクエスト時に非同期でOCSPレスポンスを取得するため、ステープルが準備できる前に最初のいくつかの接続が到達する場合があります。

Related Error Notes