2026年5月20日
2026年5月20日
WordPressのSSL証明書を更新する方法
はじめに
SSL証明書が期限切れになると、訪問者のブラウザに「この接続は安全ではありません」という警告が表示され、サイトへのアクセスが激減します。Let's Encryptは90日間有効で自動更新が前提ですが、設定ミスで自動更新が止まることがあります。
症状・原因
- ブラウザに「NET::ERR_CERT_DATE_INVALID」が表示される
- SSL証明書の有効期限が切れている
- Let's Encryptの自動更新が動いていなかった
- 有料SSL証明書の更新期限を過ぎてしまった
解決手順
ステップ1:証明書の有効期限を確認する
# 現在の証明書の有効期限を確認
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
# notBefore= : 発行日
# notAfter= : 有効期限
# Let's Encrypt の証明書一覧と期限を確認
sudo certbot certificates
# 出力例:
# Found the following certs:
# Certificate Name: example.com
# Domains: example.com www.example.com
# Expiry Date: 2024-12-31 (VALID: 30 days)
# Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
# 残り日数を数値で確認
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -enddate | \
awk -F= '{print $2}' | \
xargs -I{} bash -c 'echo "Expires: {}; Days left: $(( ( $(date -d "{}" +%s) - $(date +%s) ) / 86400 ))"'
ステップ2:Let’s Encrypt証明書を手動更新する
# ① 更新テスト(実際には更新しない)
sudo certbot renew --dry-run
# ② 全証明書を更新
sudo certbot renew
# ③ 特定のドメインのみ更新
sudo certbot renew --cert-name example.com
# ④ 強制更新(期限が30日以上残っていても更新)
sudo certbot renew --force-renewal --cert-name example.com
# ⑤ 更新後にWebサーバーを再起動
sudo systemctl reload apache2
# または
sudo systemctl reload nginx
# 更新が失敗する場合のデバッグ
sudo certbot renew --dry-run --debug
# ログを確認
sudo cat /var/log/letsencrypt/letsencrypt.log | tail -50
# よくある失敗原因:
# 1. ポート80が開いていない(ファイアウォール)
# 2. DNSが正しく設定されていない
# 3. ウェブルートのパスが間違っている
# 4. Apacheの設定エラー
# ポート80の疎通確認
curl -I http://example.com/.well-known/acme-challenge/test
ステップ3:自動更新の設定を確認・修正する
# systemd タイマーの状態を確認(Ubuntu/Debian)
sudo systemctl status certbot.timer
sudo systemctl list-timers | grep certbot
# タイマーが無効の場合は有効化
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
# crontab を確認
sudo crontab -l | grep certbot
# crontab に自動更新を追加(タイマーがない場合)
sudo crontab -e
# 以下を追加(月2回、午前3時に実行):
# 0 3 1,15 * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload apache2"
# 更新フックが正しく設定されているか確認
ls -la /etc/letsencrypt/renewal-hooks/deploy/
# Webサーバー再起動フックを設定
# Apache の場合
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh << 'EOF'
#!/bin/bash
systemctl reload apache2
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh
# Nginx の場合
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
ステップ4:証明書期限切れアラートを設定する
# cron で期限切れを監視してメール通知
cat > /usr/local/bin/check-ssl-expiry.sh << 'EOF'
#!/bin/bash
DOMAIN="example.com"
ALERT_DAYS=14
ADMIN_EMAIL="admin@example.com"
EXPIRY=$(echo | openssl s_client -connect ${DOMAIN}:443 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "${EXPIRY}" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ "${DAYS_LEFT}" -lt "${ALERT_DAYS}" ]; then
echo "SSL certificate for ${DOMAIN} expires in ${DAYS_LEFT} days (${EXPIRY})" | \
mail -s "[警告] SSL証明書の期限が${DAYS_LEFT}日後に切れます" "${ADMIN_EMAIL}"
fi
EOF
chmod +x /usr/local/bin/check-ssl-expiry.sh
# cron に追加(毎日確認)
echo "0 9 * * * root /usr/local/bin/check-ssl-expiry.sh" > /etc/cron.d/ssl-check
// functions.php: WordPress 管理画面でSSL期限を表示
add_action('admin_notices', function(): void {
if (!current_user_can('manage_options')) return;
$domain = parse_url(home_url(), PHP_URL_HOST);
$cache_key = 'ssl_expiry_days_' . md5($domain);
$days_left = get_transient($cache_key);
if ($days_left === false) {
$context = stream_context_create([
'ssl' => ['capture_peer_cert' => true],
]);
$conn = @stream_socket_client(
"ssl://{$domain}:443", $errno, $errstr, 5,
STREAM_CLIENT_CONNECT, $context
);
if ($conn) {
$params = stream_context_get_params($conn);
$cert = openssl_x509_parse(
$params['options']['ssl']['peer_certificate']
);
$expiry = $cert['validTo_time_t'] ?? 0;
$days_left = (int) (($expiry - time()) / 86400);
set_transient($cache_key, $days_left, DAY_IN_SECONDS);
fclose($conn);
}
}
if ($days_left !== false && $days_left < 14) {
echo '<div class="notice notice-error"><p>';
printf(
'<strong>SSL証明書の期限が %d 日後に切れます。</strong>早急に更新してください。',
$days_left
);
echo '</p></div>';
}
});
ステップ5:有料SSL証明書の更新
# 有料証明書の場合:CSRを生成して認証局に提出
# ① 秘密鍵を生成
openssl genrsa -out /etc/ssl/private/example.com.key 2048
# ② CSR(証明書署名要求)を生成
openssl req -new \
-key /etc/ssl/private/example.com.key \
-out /tmp/example.com.csr \
-subj "/C=JP/ST=Tokyo/L=Tokyo/O=Company/CN=example.com"
# ③ CSR の内容を確認
openssl req -text -noout -in /tmp/example.com.csr
# ④ CSR をコピーして認証局のサイトに貼り付け
cat /tmp/example.com.csr
# ⑤ 認証局から受け取った証明書を設置
# fullchain.pem と privkey.pem を適切な場所に配置し
# Apache/Nginx の設定を更新してリロード
sudo systemctl reload apache2
注意事項
- Let's Encrypt の証明書は有効期限が30日を切るまで
certbot renewは更新しません。--force-renewalは不要な更新を発生させ、レートリミット(週5回)に引っかかる可能性があるため、通常は使用しないでください - 証明書を更新してもWebサーバー(Apache/Nginx)をリロードしないと、古い証明書が引き続き使用されます。更新後は必ずリロードしてください
- ワイルドカード証明書(
*.example.com)はHTTP認証ではなくDNS認証が必要です。certbot certonly --manual --preferred-challenges dnsで手動更新が必要です
まとめ
SSL証明書更新は①certbot certificatesで残り日数を確認、②certbot renew --dry-runでテスト後にcertbot renewで更新、③systemctl status certbot.timerで自動更新タイマーを確認・有効化、④/etc/letsencrypt/renewal-hooks/deploy/にWebサーバーリロードフックを設置、⑤管理画面への期限アラートと日次cronによる監視で事前に気づける仕組みを構築します。