言語を切り替える
テーマを切り替える

SSL証明書の設定:Let's Encryptの自動更新とマルチドメイン管理

監視アラートのメールがチーム全体を叩き起こしました。サイトにアクセスできず、ユーザーからのクレーム電話がサポートに殺到。ブラウザを開いてみると——赤い警告ページに「このサイトのセキュリティ証明書は期限切れです」。もう終わりです。

起き上がってサーバーに接続すると、SSL証明書が昨夜に期限切れになっていたことが判明。手動更新で5時まで奮闘し、戻って2時間だけ寝てまた出勤です。

この一件以来、こう考えるようになりました。証明書の期限切れを完全になくせないものか、と。その後Let’s Encryptに触れて、無料SSL証明書の自動更新がとっくに成熟していることを知ったのです。ただ多くの開発者は——当時の自分も含めて——いまだに手動管理という古いやり方に留まっていました。

この記事が解決したい課題は明確です。SSL証明書を二度と期限切れにせず、マルチドメイン管理も混乱しないようにすること。個人ブログでも会社のサービスでも、読み終えたらそのまま設定に取りかかれます。


Let’s Encryptとは?まず仕組みを理解する

正直なところ、Let’s Encryptを使っていてもその仕組みを理解していない人は多いです。仕組みを知っておけば、問題が起きたときにすばやく原因を特定できます。

認証局(CA)の役割

Let’s Encryptは認証局、略してCAです。その立ち位置は非常に明確で、無料・自動化・オープンです。2016年にサービスを開始してから、わずか数年でHTTPSの普及を後押ししました——今では2億を超えるアクティブな証明書があり、世界中のブラウザでの信頼率は100%です。

2億+
アクティブな証明書の数

従来のCA(たとえばDigiCertやGeoTrust)は料金が高く、手続きが煩雑で、しかも人手による審査が必要でした。Let’s Encryptは違います。完全に自動化されていて、申請するとそれを検証し、すぐに発行してくれます。証明書の有効期限は90日。短く見えますが、自動更新の仕組みと組み合わせれば、かえって安全です。なぜか。証明書が短いほど、漏洩リスクが小さくなるからです。

ACMEプロトコル:自動化の核心

Let’s Encryptが使っているのはACMEプロトコル(Automated Certificate Management Environment)で、RFC 8555規格です。このプロトコルは、ドメイン所有権をどう自動検証し、どう証明書を発行するかを定義しています。

検証方式は3種類あります

  1. HTTP-01検証:最もよく使われます。CAがドメイン配下の特定パス(/.well-known/acme-challenge/)にアクセスし、検証トークンが含まれているかチェックします。あなたがそのドメインを管理していることを証明します。
  2. DNS-01検証:ワイルドカード証明書では必ずこれを使います。CAがDNSのTXTレコードに検証トークンがあるかチェックします。ウェブサーバーは不要ですが、DNS APIの権限が必要です。
  3. TLS-ALPN-01検証:あまり使われず、特殊なシナリオに向いています。

HTTP-01が最もシンプルですが、80番ポートにアクセスできることが前提です。DNS-01は柔軟で、社内サービスやワイルドカードに向いています。

Certbot:公式推奨のクライアント

CertbotはLet’s Encryptが公式に推奨するクライアントツールです。証明書の申請、ウェブサーバーの設定、自動更新の設定まで、一連の流れを手伝ってくれます。

Certbotの主な機能

  • 複数の検証方式に対応
  • Nginx/Apacheの設定を自動変更(プラグイン経由)
  • systemd timerまたはcron jobを自動設定
  • 更新テスト用コマンドを提供(dry-run)

これらの仕組みを理解しておけば、後で設定中に問題が起きても、どこを調べればよいか分かります。


単一ドメインのSSL証明書設定:ゼロから始める

まずは最もシンプルなシナリオから入りましょう。1つのドメイン、1台のサーバーです。基本の流れを押さえれば、マルチドメインも自然に理解できます。

Certbotをインストールする

システムによってインストール方法が異なります。Ubuntu/Debianが最もシンプルで、私はSnapを推奨します——公式もこの方式を推奨しており、バージョンの更新も迅速です。

Ubuntu/Debian(Snap方式)

# Snapをインストール(未導入の場合)
sudo apt update
sudo apt install snapd

# Certbotをインストール
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

CentOS/RHEL

sudo yum install certbot
# または
sudo dnf install certbot

インストールが終わったら、テストしてみましょう:

certbot --version
# 次のような出力になるはず:certbot 2.11.0

証明書を取得する:3つの方式

Certbotは証明書を取得する方式を3つ提供しています。具体的なニーズに合わせて選びましょう。

方式1:Nginxプラグインによる自動設定(初心者向け)

最も手軽です。CertbotがNginx設定を自動で変更し、証明書の申請、HTTPSの設定、リダイレクトの設定まで、コマンド1つで完了します:

sudo certbot --nginx -d example.com -d www.example.com

実行中にいくつか質問されます:

  • メールアドレス(緊急通知用)
  • 利用規約への同意
  • メールを共有するか(Noを選択)
  • HTTPからHTTPSへのリダイレクト(Yesを選択、より安全)

完了すると、Nginx設定がすでに書き換えられています。証明書のパスが表示されます:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem

方式2:Apacheプラグインによる自動設定

Nginxと同様で、プラグインをApacheに変えるだけです:

sudo certbot --apache -d example.com -d www.example.com

方式3:証明書の取得のみ(手動設定)

Certbotに設定を変更させたくない場合や、別のウェブサーバー(Caddy、Node.js)を使っている場合は、certonlyモードを使えます:

sudo certbot certonly --webroot \
  -w /var/www/html \
  -d example.com \
  -d www.example.com

-wはWebルートディレクトリを指定します。Certbotがここに検証ファイルを置きます。証明書を取得した後は、自分でウェブサーバーを設定します。

証明書が有効か確認する

証明書の申請が完了したら、まず正常に動作するか確認しましょう。

証明書ファイルを確認する

sudo ls -la /etc/letsencrypt/live/example.com/

4つのファイルが見えるはずです:

  • cert.pem:証明書本体
  • chain.pem:中間証明書チェーン
  • fullchain.pem:完全な証明書チェーン(Nginxはこれを使用)
  • privkey.pem:秘密鍵(Nginxはこれを使用)

SSL Labsのテスト

https://www.ssllabs.com/ssltest/ にアクセスし、自分のドメインを入力します。テストで評価(A+からF)が出ます。目標は少なくともAを取ることです。

よくある問題:

  • BまたはC:TLSバージョンが古い、暗号スイートが弱い。後で最適化方法を説明します。
  • F:証明書チェーンが不完全。Nginx設定がcert.pemではなくfullchain.pemを使っているか確認しましょう。

ブラウザでアクセスする

https://example.comを直接開くと、アドレスバーに鍵アイコンが表示されるはずです。鍵アイコンをクリックすると証明書の詳細が見え、発行者に「Let’s Encrypt」と書かれています。


自動更新の設定:期限切れの心配は永遠に無用

Let’s Encrypt証明書の有効期限は90日だけです。短く見えますが、自動更新と組み合わせれば、むしろ利点になります——証明書のローテーションが速く、漏洩リスクが低いからです。

Certbotの自動更新の仕組み

Certbotをインストールするとき、更新の仕組みも自動で設定されます。システムによって方式が異なります:

Systemd Timer(モダンなLinux)

Certbotのインストール後、certbot.timercertbot.serviceが作成されます。Timerは1日2回実行され、証明書がまもなく期限切れ(30日以内)かチェックします。期限が近ければ、Serviceをトリガーして更新を実行します。

Timerの状態を確認します:

sudo systemctl list-timers | grep certbot

次のような出力になります:

NEXT                         LEFT          LAST                         PASSED       UNIT           ACTIVATES
Thu 2026-04-02 12:00:00 UTC  1h left       Thu 2026-04-02 00:00:00 UTC  11h ago      certbot.timer  certbot.service

次回の実行時刻と前回の実行時刻が確認できます。

Cron Job(従来の方式)

システムにsystemdがない場合(古いバージョンのCentOS)は、Certbotがcron jobを設定します。確認します:

sudo crontab -l
# または
cat /etc/cron.d/certbot

典型的な設定:

0 0,12 * * * root certbot renew --quiet

毎日0時と12時に更新チェックを実行します。

自動更新が動作するか確認する

TimerやCronが見えるだけでは不十分で、更新が本当に実行できるか確認する必要があります。

Dry Runテスト

Certbotはテスト用コマンドを用意しています。実際には更新せず、シミュレーションするだけです:

sudo certbot renew --dry-run

次のような出力になります:

Processing /etc/letsencrypt/renewal/example.com.conf
Cert not due for renewal, but simulating renewal for dry run
...
The dry run was successful.

「successful」が見えれば、自動更新の設定が正しいということです。

更新設定ファイルを確認する

各証明書には対応する更新設定ファイルがあります:

cat /etc/letsencrypt/renewal/example.com.conf

ファイルには証明書申請時のパラメータや検証方式などが記録されています。更新時にこの設定が読み込まれます。

更新後のウェブサーバー自動リロードを設定する

証明書を更新した後も、ウェブサーバーはまだ古い証明書を使っています。設定をリロードして初めて反映されます。

Deploy Hook(推奨)

更新成功後にコマンドを自動実行します:

sudo certbot renew --deploy-hook "systemctl reload nginx"

または更新設定ファイルに追加します:

# /etc/letsencrypt/renewal/example.com.conf を編集
# 末尾に追加:
deploy_hook = systemctl reload nginx

Post Hook(毎回実行)

更新の成否にかかわらず実行します:

sudo certbot renew --post-hook "systemctl reload nginx"

違いは、Deploy Hookは更新成功時のみトリガーされるのに対し、Post Hookは毎回トリガーされる点です。Deploy Hookを使うほうが合理的です。

更新に失敗したらどうするか?

自動更新は万能ではなく、たまに失敗します。よくある原因と解決方法を見ていきます。

DNS解決の問題

ドメインのDNSを変更したのに、検証時にCAがまだ古いIPを参照している場合です。DNSの反映(TTLの時間)を待つか、手動で更新します:

sudo certbot renew --force-renewal

ファイアウォールやポートの問題

HTTP-01検証では80番ポートにアクセスできる必要があります。ファイアウォールを確認します:

sudo ufw status
sudo iptables -L -n

一時的に80番ポートを開放します:

sudo ufw allow 80/tcp

権限の問題

証明書ファイルの権限が誤っている場合です。確認します:

sudo ls -la /etc/letsencrypt/live/
sudo ls -la /etc/letsencrypt/archive/

ウェブサーバーのユーザー(www-dataなど)が証明書を読み取れることを確認しましょう。

更新ログを確認する

失敗時は詳細なログを確認します:

sudo tail -f /var/log/letsencrypt/letsencrypt.log

ログに失敗の原因が記録されます。ログのヒントに従って解決しましょう。


マルチドメインSSL証明書の管理:統合と分散の戦略

複数のドメインを持つと、証明書の管理戦略が重要になります。うまくやらないと、ぐちゃぐちゃになります——更新タイミングがばらばら、証明書ファイルがあちこちに散らばり、設定ミスも起きやすくなります。

単一証明書・マルチドメイン(SANモード)

最も推奨される方式です。1枚の証明書に複数のドメインを含めます。Certbotの申請時に直接指定します:

sudo certbot --nginx \
  -d example.com \
  -d www.example.com \
  -d api.example.com \
  -d admin.example.com

メリット

  • 一括更新:1回の更新ですべてのドメインが更新される
  • ファイルの集約:証明書ディレクトリが1つだけ
  • 設定がシンプル:ウェブサーバーは1つの証明書パスを参照するだけ

SAN(Subject Alternative Names)拡張:これは証明書内のフィールドで、含まれるすべてのドメインを列挙します。ブラウザはアクセスするドメインがSANリストにあるかチェックします。

証明書に含まれるドメインを確認します:

sudo certbot certificates

次のような出力になります:

Found the following certs:
  Certificate Name: example.com
    Domains: example.com www.example.com api.example.com admin.example.com
    Expiry Date: 2026-07-01 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem

ワイルドカード証明書(Wildcard)

ワイルドカード証明書はワイルドカードですべてのサブドメインに一致します:*.example.com。1枚の証明書でblog.example.comapi.example.comadmin.example.comなどをカバーします。

必ずDNS-01検証を使います:HTTP-01はワイルドカードに対応していません。CertbotはTXTレコードを追加するためにDNS APIの権限が必要です。

DNSプラグインを設定する

DNSサービス事業者によってプラグインが異なります。Cloudflareが最もよく使われます:

# Cloudflareプラグインをインストール
sudo snap install certbot-dns-cloudflare

# 認証情報ファイルを作成
sudo nano /root/.secrets/certbot/cloudflare.ini

認証情報ファイルの内容:

dns_cloudflare_api_token = your_cloudflare_api_token

API TokenはCloudflareのコンソールで生成し、権限は「DNS:Edit」を選びます。

ワイルドカード証明書を申請する

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
  -d "*.example.com" \
  -d example.com

注意:*.example.comexample.comを同時に申請する必要があります。ワイルドカードは裸ドメインに一致しません。

ワイルドカード証明書の制限

第1レベルのサブドメインにのみ一致*.example.comsub.example.comに一致しますが、sub.sub.example.comには一致しません。

第2レベルのサブドメインがある場合は、別途申請が必要です:

sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/certbot/cloudflare.ini \
  -d "*.example.com" \
  -d "*.api.example.com" \
  -d example.com

これでapi.example.comv1.api.example.comをカバーします。

複数証明書の管理戦略

単一証明書・マルチドメインを使うのはどんなときか?複数証明書を使うのはどんなときか?

サービスごとにグループ化(推奨)

Webサービス群:メインサイト、ブログ、ドキュメント

sudo certbot --nginx -d example.com -d www.example.com -d blog.example.com -d docs.example.com

APIサービス群:APIエンドポイント、管理画面

sudo certbot --nginx -d api.example.com -d admin.example.com -d v1.api.example.com

社内サービス群:監視、ログ、社内ツール

sudo certbot certonly --dns-cloudflare -d "*.internal.example.com"

メリット

  • 更新の影響範囲を制御できる:APIサービスの更新がWebサービスに影響しない
  • 権限の分離:社内サービスの証明書権限を個別に管理できる
  • 障害の切り分け:ある証明書の問題が他のサービスに影響しない

ドメインの階層ごとにグループ化

ワイルドカード+単一ドメインの組み合わせ:

# ワイルドカードですべてのサブドメインをカバー
sudo certbot certonly --dns-cloudflare -d "*.example.com" -d example.com

# 特殊なサブドメインは個別の証明書に(特別な設定が必要な場合)
sudo certbot --nginx -d secure.example.com

証明書ファイルのパスを詳しく解説

証明書ディレクトリの構造を理解すれば、複数証明書を管理しても混乱しません。

実際の証明書ディレクトリ/etc/letsencrypt/live/[証明書名]/

シンボリックリンクが最新の証明書を指しています。更新のたびに、リンクが新しい証明書ファイルに更新されます。

sudo ls -la /etc/letsencrypt/live/example.com/
lrwxrwxrwx 1 root root  42 Apr  2 12:00 cert.pem -> ../../archive/example.com/cert2.pem
lrwxrwxrwx 1 root root  43 Apr  2 12:00 chain.pem -> ../../archive/example.com/chain2.pem
lrwxrwxrwx 1 root root  44 Apr  2 12:00 fullchain.pem -> ../../archive/example.com/fullchain2.pem
lrwxrwxrwx 1 root root  40 Apr  2 12:00 privkey.pem -> ../../archive/example.com/privkey2.pem

証明書アーカイブディレクトリ/etc/letsencrypt/archive/[証明書名]/

更新ごとの証明書履歴を保存します。ファイル名には番号が付きます:cert1.pemcert2.pemなど。

更新設定ディレクトリ/etc/letsencrypt/renewal/[証明書名].conf

証明書申請時のパラメータを記録します。更新時にこのファイルが読み込まれます。

# ある証明書の更新設定を確認
cat /etc/letsencrypt/renewal/example.com.conf

設定には次が含まれます:

  • 検証方式(webroot、nginx、dns-cloudflare)
  • 元のドメインリスト
  • Deploy Hook など

高度な設定と最適化:セキュリティとパフォーマンスのバランス

基本設定が完了したら、さらに最適化できます。目標はセキュリティとパフォーマンスの両立です。

HTTP/2とOCSP Stapling

HTTP/2はパフォーマンスを向上させ、OCSP Staplingは検証の遅延を減らします。

NginxでHTTP/2を設定する

server {
    listen 443 ssl http2;  # http2 を追加
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # ... その他の設定
}

http2listenディレクティブの後ろに追加します。Nginxをリロードします:

sudo nginx -t
sudo systemctl reload nginx

OCSP Staplingの設定

OCSP(Online Certificate Status Protocol)は証明書の状態を検証します。Staplingにより、サーバーが検証結果を事前に取得しておくので、クライアントが個別にCAへリクエストする必要がなくなります。

server {
    # ... SSL設定

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
}

設定すると、SSL Labsのテストで「OCSP Stapling: Yes」が確認できます。

セキュリティ強化:古いバージョンのTLSを無効化する

TLS 1.0と1.1はすでに安全ではありません。2020年以降、主要ブラウザはすべて廃止しました。

server {
    # TLS 1.2 と 1.3 のみ残す
    ssl_protocols TLSv1.2 TLSv1.3;

    # 推奨の暗号スイート(セキュリティと互換性を両立)
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

    ssl_prefer_server_ciphers on;

    # SSL セッションキャッシュ(パフォーマンス向上)
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
}

設定すると、SSL LabsのテストでAまたはA+に到達するはずです。

HSTSヘッダーの設定

HSTS(HTTP Strict Transport Security)はブラウザにHTTPSでのみアクセスするよう強制します。設定すると、ブラウザはこのドメインが必ずHTTPSを使うことを記憶し、ユーザーがhttp://と入力しても自動でリダイレクトします。

server {
    # ... SSL設定

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

パラメータの説明:

  • max-age=31536000:有効期限は1年(秒)
  • includeSubDomains:すべてのサブドメインを含める
  • preload:ブラウザのプリロードリストへの登録を許可

注意:HSTSを設定した後は、一時的にHTTPが必要なとき(テストなど)でも、ブラウザがアクセスを拒否する場合があります。慎重に使いましょう。

監視とアラート:問題を能動的に見つける

自動更新は万能ではありません。万一自動更新が失敗したら、事前に知る必要があります。証明書の期限の1週間前にアラートを受け取れば、手動で対処する時間がまだあります。

63%
証明書障害は期限切れが原因

シンプルな監視スクリプト

証明書の残り日数をチェックするスクリプトを作成します:

#!/bin/bash
# /usr/local/bin/check-ssl-expiry.sh

DOMAIN="example.com"
EXPIRY_DAYS=$(openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)

EXPIRY_DATE=$(date -d "$EXPIRY_DAYS" +%s)
CURRENT_DATE=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_DATE - $CURRENT_DATE) / 86400 ))

if [ $DAYS_LEFT -lt 7 ]; then
    echo "WARNING: SSL certificate for $DOMAIN expires in $DAYS_LEFT days"
    # メールでアラート(メールサービスの設定が必要)
    mail -s "SSL Certificate Expiry Warning" admin@example.com <<< "SSL certificate for $DOMAIN expires in $DAYS_LEFT days"
fi

cronに追加して、毎日チェックします:

0 6 * * * /usr/local/bin/check-ssl-expiry.sh

Certbotの自動通知

Certbotは更新に失敗すると、証明書申請時のメールアドレスにメールを送ります。メールアドレスが正しく、メールを受け取れることを確認しておきましょう。


よくある問題と解決策

設定の過程ではさまざまな問題に遭遇するかもしれません。ここではよくある落とし穴と解決方法をまとめます。

証明書の申請に失敗する

原因1:ドメインのDNSがサーバーに解決されていない

証明書を申請するとき、CAはドメイン所有権を検証します。HTTP-01検証ではドメインにアクセスする必要があります。DNSがまだ解決していないと、検証に失敗します。

DNSを確認します

dig example.com +short
# または
nslookup example.com

返ってくるIPが自分のサーバーIPであることを確認します。

解決:DNSの反映を待ちます。TTLの時間(通常は数分から数時間)が経ってから再試行します。

原因2:80番ポートが占有されている、またはファイアウォールにブロックされている

HTTP-01検証は80番ポート経由でアクセスします。ポートが他のプロセスに占有されていたり、ファイアウォールに遮断されていたりすると、検証に失敗します。

ポートの占有を確認します

sudo netstat -tulpn | grep :80
sudo lsof -i :80

Nginx/Apacheによる占有でなければ、占有しているプロセスを停止します:

sudo systemctl stop 占有しているサービス名

ファイアウォールを確認します

sudo ufw status
# または
sudo iptables -L -n

80番ポートを開放します:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

原因3:Webrootディレクトリの権限問題

certonly --webroot方式を使うとき、CertbotはWebルートディレクトリに検証ファイルを作成します。権限が足りないと失敗します。

ディレクトリ権限を確認します

ls -la /var/www/html/.well-known/

Certbotのユーザー(通常はroot)が書き込めることを確認します。

手動でディレクトリを作成します

sudo mkdir -p /var/www/html/.well-known/acme-challenge
sudo chown -R www-data:www-data /var/www/html/.well-known

更新失敗への対処

自動更新はたまに失敗します。慌てないでください。まずログを確認し、それから的を絞って解決します。

Certbotのログを確認する

sudo tail -100 /var/log/letsencrypt/letsencrypt.log

ログに失敗の原因が表示されます。よくあるエラー:

  • Connection refused:ポートの問題
  • DNS problem: NXDOMAIN:DNS解決の問題
  • Rate limit exceeded:申請回数の上限超過

手動で強制更新する

自動更新が失敗したら、手動で更新します:

sudo certbot renew --force-renewal

--force-renewalは期限の有無にかかわらず強制的に更新します。

更新設定を確認する

更新設定ファイルが壊れていても失敗します。確認します:

cat /etc/letsencrypt/renewal/example.com.conf

設定が正しいか確認します。壊れている場合は、証明書を削除して再申請します:

sudo certbot delete --cert-name example.com
sudo certbot --nginx -d example.com -d www.example.com

複数証明書の競合

複数の証明書があると、ウェブサーバーが誤った証明書を参照することがあります。

Nginxの証明書パスが誤っている

Nginx設定を確認します:

sudo nginx -T | grep ssl_certificate

各server blockが使う証明書パスが正しいか確認します。

よくあるミス

  • fullchain.pemではなくcert.pemを使っている(証明書チェーンが不完全)
  • 誤った証明書ディレクトリを参照している(証明書名とドメインが不一致)

証明書名とドメインが不一致

Certbotは最初のドメインを証明書名にします。たとえば:

sudo certbot --nginx -d api.example.com -d example.com

証明書名はapi.example.comで、パスは/etc/letsencrypt/live/api.example.com/です。

Nginx設定に/etc/letsencrypt/live/example.com/と書くと、証明書が見つかりません。

証明書名を確認します

sudo certbot certificates

証明書名とパスが一致することを確認します。

ワイルドカード証明書の制限

ワイルドカード証明書は便利ですが、制約があります。

第1レベルのサブドメインにのみ一致

*.example.comsub.example.comに一致しますが、sub.sub.example.comには一致しません。

第2レベルのサブドメインがある場合は、追加の証明書が必要です:

# ワイルドカード証明書(第1レベル)
sudo certbot certonly --dns-cloudflare -d "*.example.com" -d example.com

# 第2レベルのサブドメイン証明書
sudo certbot certonly --dns-cloudflare -d "*.api.example.com"

裸ドメインに一致しない

*.example.comexample.com(裸ドメイン)に一致しません。必ず別途-d example.comを追加します。

誤った例

# 誤り:裸ドメインにアクセスできない
sudo certbot certonly --dns-cloudflare -d "*.example.com"

正しい例

# 正しい:裸ドメインも同時に含める
sudo certbot certonly --dns-cloudflare -d "*.example.com" -d example.com

まとめ:手動から自動への進化

SSL証明書に奮闘する過程は、実は手動から自動への進化です。従来のCAの手動フローは、Let’s Encryptの自動化体系のもとでシンプルかつ信頼できるものになりました。

重要ポイントの振り返り

  1. 仕組みの理解:ACMEプロトコルが自動検証と発行のフローを定義します。HTTP-01とDNS-01は2つの検証方式で、それぞれ適したシナリオがあります。
  2. 自動更新:Certbotのインストール後、systemd timerまたはcron jobが自動設定されます。更新のトリガー条件は証明書の期限の30日前で、1日2回チェックします。
  3. マルチドメイン管理:SANモード(単一証明書・マルチドメイン)は統合管理に向き、ワイルドカード証明書は大量のサブドメインに向きます。サービスごとのグループ化が推奨戦略です。
  4. セキュリティ最適化:HTTP/2、OCSP Stapling、古いバージョンのTLSの無効化、HSTSの設定。これらでSSL Labsの評価をA+にできます。
  5. 監視とアラート:自動更新は万能ではありません。証明書の残り日数を能動的に監視し、問題を早めに見つけましょう。

今後の最適化の方向性

複数台のサーバーや大量のドメインを管理するなら、次を検討できます:

  • 自動化プラットフォーム:Cert Manager(Kubernetes)、Traefik(自動SSL)など
  • 証明書監視サービス:SSL Monitor、Uptime Robotなど
  • CI/CD統合:デプロイ時に証明書の状態を自動チェック

証明書管理は、いったん自動化してしまえば、もう気にする必要がなくなります。サイトが安全になり、ユーザーから信頼され、検索エンジンにも好まれます。深夜3時のアラートメールは、完全に過去のものになります。

Let's Encrypt SSL証明書の自動更新を設定する

Certbotのインストールから自動更新の設定まで、SSL証明書設定の全工程を解説し、サイトのHTTPSが期限切れにならないようにします

⏱️ 目安時間: 30 分

  1. 1

    ステップ1: Certbotをインストールする

    システムに応じてインストール方法を選びます:

    • Ubuntu/Debian(推奨):sudo snap install --classic certbot
    • CentOS/RHEL:sudo yum install certbot
    • インストール確認:certbot --version
  2. 2

    ステップ2: SSL証明書を申請する

    用途に合った申請方法を選びます:

    • Nginx自動設定:sudo certbot --nginx -d example.com -d www.example.com
    • Apache自動設定:sudo certbot --apache -d example.com -d www.example.com
    • 証明書取得のみ:sudo certbot certonly --webroot -w /var/www/html -d example.com
  3. 3

    ステップ3: 自動更新を確認する

    Certbotが更新の仕組みを自動設定しているか確認します:

    • Systemd Timer:sudo systemctl list-timers | grep certbot
    • Dry Runテスト:sudo certbot renew --dry-run
    • 出力に「successful」が含まれることを確認
  4. 4

    ステップ4: 更新後の自動リロードを設定する

    更新設定ファイルにDeploy Hookを追加します:

    • ファイルを編集:sudo nano /etc/letsencrypt/renewal/example.com.conf
    • 設定を追加:deploy_hook = systemctl reload nginx
    • またはコマンドで:sudo certbot renew --deploy-hook "systemctl reload nginx"
  5. 5

    ステップ5: セキュリティ強化を設定する

    Nginx設定にセキュリティ最適化を追加します:

    • 古いTLSを無効化:ssl_protocols TLSv1.2 TLSv1.3;
    • HTTP/2を有効化:listen 443 ssl http2;
    • OCSP Stapling:ssl_stapling on;
    • HSTSヘッダー:add_header Strict-Transport-Security "max-age=31536000" always;
  6. 6

    ステップ6: 監視とアラートを設定する

    証明書の期限切れ監視スクリプトを作成します:

    • スクリプトを作成:sudo nano /usr/local/bin/check-ssl-expiry.sh
    • Cronを追加:0 6 * * * /usr/local/bin/check-ssl-expiry.sh
    • Certbotのメール通知が有効であることを確認

FAQ

Let's Encrypt証明書の有効期限はなぜ90日しかないのですか?
90日の有効期限は自動更新の仕組みと組み合わせることで、かえって安全になります。証明書のローテーションが速いため、漏洩リスクが小さくなります。秘密鍵が漏れても90日後に自動的に失効するので、長期的なリスクを下げられます。
HTTP-01とDNS-01の検証方式にはどのような違いがありますか?
HTTP-01:CAがドメインの特定パスにアクセスして検証する方式で、最もシンプルです。80番ポートにアクセスできる必要があります。単一ドメイン証明書に向いています。

DNS-01:CAがDNSのTXTレコードをチェックして検証する方式で、DNS APIの権限が必要です。ワイルドカード証明書では必ずこの方式を使います。社内サービスや大量のサブドメインに向いています。
ワイルドカード証明書 *.example.com はどのドメインに一致しますか?
第1レベルのサブドメインにのみ一致します:sub.example.com、api.example.com、blog.example.com など。

一致しないケース:
• 第2レベルのサブドメイン:sub.sub.example.com(別途 *.sub.example.com の申請が必要)
• 裸ドメイン:example.com(必ず別途 -d example.com を追加)
Certbotの自動更新はいつトリガーされますか?
証明書の期限の30日前に自動でトリガーされます。Systemd TimerまたはCron Jobが1日2回(通常は0時と12時)チェックし、証明書がまもなく期限切れになると更新を実行します。更新成功後はDeploy Hookによってウェブサーバーが自動でリロードされます。
SSL LabsのテストでBやCの評価になったらどう解決しますか?
よくある原因と解決方法:

• TLSバージョンが古い:Nginxで ssl_protocols TLSv1.2 TLSv1.3; を設定
• 暗号スイートが弱い:推奨の暗号スイートを設定(記事の第6節を参照)
• 証明書チェーンが不完全:cert.pem ではなく fullchain.pem を使用
• OCSP Staplingがない:ssl_stapling on; の設定を追加

設定後にNginxをリロードして再テストすると、AまたはA+に到達するはずです。
マルチドメインでは単一証明書と複数証明書のどちらを使うべきですか?
サービスごとにグループ化する戦略を推奨します:

• 単一証明書・マルチドメイン(SANモード):関連するドメインに向いています。一括更新でき、設定もシンプルです。例:Webサービス群(example.com、www.example.com、blog.example.com)
• 複数証明書でグループ化:異なるサービスに向いています。障害の切り分けと権限の分離ができます。例:Webサービス、APIサービス、社内サービスを分けて管理
• ワイルドカード証明書:大量のサブドメインに向いており、証明書の数を減らせます。例:*.example.com ですべての第1レベルサブドメインをカバー
証明書の更新に失敗したらどうすればよいですか?
まずログを確認して原因を特定します:sudo tail -100 /var/log/letsencrypt/letsencrypt.log

よくある失敗原因:
• DNS解決の問題:DNSの反映を待つか、手動で更新 --force-renewal
• ポートの占有:80番ポートを確認し、占有しているサービスを一時停止
• ファイアウォールによるブロック:80/443番ポートを開放
• 権限の問題:証明書ファイルの権限を確認

解決後に手動で更新:sudo certbot renew --force-renewal

9分で読めます · 公開日: 2026年4月2日 · 更新日: 2026年6月8日

コメント

GitHubアカウントでログインしてコメントできます