Let’s EncryptによるSSLサーバー証明書の取得、自動更新設定(2021年3月版)

isd1. はじめに

2019年1月に「Let’s EncryptによるSSLサーバー証明書の取得、自動更新設定(2019年1月版)」という記事を書きました。
最近、証明書を取得、更新するためのcertbotコマンドの推奨インストール方法が変わりましたので、2021年3月版としてまとめ直します。

なお、以下の設定手順は、サーバーOSはCentOS 7で、2021年3月時点のものです。
Apache, Nginxについては、Let’s Encryptに関わる設定のみ記載し、Let’s Encryptに無関係な基本的な設定は、ここでは記載しません。

コマンドはrootユーザーで実行する想定です。
必要に応じて、sudoに置き換えてください。

(参考)
・Certbotのユーザーガイド
https://certbot.eff.org/docs/using.html

・Let’s Encrypt で証明書を発行して運用するための nginx の設定 – ymyzk’s blog
https://blog.ymyzk.com/2016/02/nginx-config-for-lets-encrypt/

(2021.10.19追記)
Snapを使用しないLet’s Encryptの設定については、以下にまとめました。
ご参考まで。

・Let’s EncryptによるSSLサーバー証明書の取得、自動更新設定(Snapを使用しない版)
https://inaba-serverdesign.jp/blog/20211019/pip-lets-encrypt-ssl-certificate-update-html.html

isd2. 要件

Let’s EncryptによるSSLサーバー証明書の取得、自動更新の要件は次のとおりとします。

  • WebサーバーソフトウェアはApacheもしくはNginxとし、事前にインストール済みとする。
  • Webサイトのダウンタイムが(ほぼ)生じないよう、更新時に、Apache, NginxなどのWebサーバーは停止せず、更新後の再起動のみとする。
  • Let’s Encryptによる証明書取得または更新の認証アクセス時、Webコンテンツディレクトリにはアクセスさせない。
  • 常時SSL化している状態で、正しく更新できる。
  • 1台のサーバーで複数の証明書を使用していても、正しく更新できるようにする。
  • ログをしっかり出力、保存する。

また、今回証明書を設置するドメイン名(FQDN)は、ssltest2021.inaba-serverdesign.jp とします。
Let’s Encrypt側の認証サーバーから、http(s)://ssltest2021.inaba-serverdesign.jp/ としてこちらのサーバーにアクセスできるよう、DNSでAレコードを設定済みです。

ssltest2021.inaba-serverdesign.jp	A	<サーバーのグローバルIPアドレス>

 

isd3. SSLサーバー証明書の取得と設定

3-1. 既存Let’s Encryptクライアントのアンインストール

もし、サーバーにLet’s Encryptクライアントcertbotをインストール済みならば、混同しないよう、アンインストールします。

※certbotをアンインストールしても、取得済みの証明書ファイルは削除されないので、ご安心ください。

EPEL版をインストールしていれば、yumコマンドで削除します。

 # yum remove certbot

 

githubから git clone コマンドでインストールした場合は、インストール先ディレクトリと /opt/eff.org ディレクトリを削除します。
以下は、インストール先が /usr/local/certbot の場合です。

 # rm -rf /usr/local/certbot/ /opt/eff.org/

 

3-2. snapdのインストール

Let’s Encryptが新しく推奨する、Snap版certbotコマンドをインストールしますが、まずは、パッケージ管理システムのSnapをインストールします。

※Snapについては、のちほど補足しますので、ここではあまり気にせず、推奨の手順どおりに実行しましょう。

Let’s Encrypt公式および、Snap公式のインストール手順に従います。

・certbot instructions, None of the above on CentOS/RHEL 7
https://certbot.eff.org/lets-encrypt/centosrhel7-other

・Installing snap on CentOS – snapcraft
https://snapcraft.io/docs/installing-snap-on-centos

EPELリポジトリからSnapをインストールするので、EPELがインストールされなければ、インストールします。

 # yum install epel-release

 

EPELリポジトリからSnapをインストールします。

 # yum --enablerepo=epel install snapd

--
...
インストール:
  snapd.x86_64 0:2.49-2.el7

インストール:
  snapd.x86_64 0:2.49-2.el7

依存性関連をインストールしました:
  fuse.x86_64 0:2.9.2-11.el7
  fuse-libs.x86_64 0:2.9.2-11.el7
  libzstd.x86_64 0:1.4.9-1.el7
  snap-confine.x86_64 0:2.49-2.el7
  snapd-selinux.noarch 0:2.49-2.el7
  squashfs-tools.x86_64 0:4.3-0.21.gitaae0aff4.el7
  squashfuse.x86_64 0:0.1.102-1.el7
  squashfuse-libs.x86_64 0:0.1.102-1.el7
...
--

 

snapdのサービス自動起動設定を行いつつ、起動します。

 # systemctl enable --now snapd.socket

--
Created symlink from /etc/systemd/system/sockets.target.wants/snapd.socket to /usr/lib/systemd/system/snapd.socket.
--

 

classic snapをサポートするため、シンボリックリンクを作成します。

 # ln -s /var/lib/snapd/snap /snap

 

coreパッケージをインストールします。

 # snap install core

--
2021-03-30T13:12:34+09:00 INFO Waiting for automatic snapd restart...
Warning: /var/lib/snapd/snap/bin was not found in your $PATH. If you've not
         restarted your session since you installed snapd, try doing that.
         Please see https://forum.snapcraft.io/t/9469 for more details.

core 16-2.49.1 from Canonical? installed
--

 

coreパッケージを最新バージョンにアップデートします。
(今回は、すでに最新バージョンでした。)

 # snap refresh core

--
snap "core" has no updates available
--

 

ちなみに、snap install や snap refresh コマンドを実行したときに、以下のようなエラーメッセージが出力される場合があります。

error: too early for operation, device not yet seeded or device model not acknowledged

 

error: cannot refresh "core": unexpectedly empty response from the server (try
       again later)

 

snapコマンドのバグのような気がしますが、Snapを極めたいわけではないので(笑)、ここではあまり気にせず、何度か同じコマンドを実行してみれば、うまくいくはずです。

Snapのバージョンを確認してみます。

 # snap --version

--
snap    2.49-2.el7
snapd   2.49-2.el7
series  16
centos  7
kernel  3.10.0-1062.12.1.el7.x86_64
--

 

3-3. Let’s Encryptクライアントのインストール

Snapからcertbotコマンドをインストールします。

 # snap install --classic certbot

--
Warning: /var/lib/snapd/snap/bin was not found in your $PATH. If you've not
         restarted your session since you installed snapd, try doing that.
         Please see https://forum.snapcraft.io/t/9469 for more details.

certbot 1.13.0 from Certbot Project (certbot-eff?) installed
--

 

/snap/bin にインストールされたので、使いやすいように /usr/bin/certbot としてシンボリックリンクを作成。

 # ln -s /snap/bin/certbot /usr/bin/certbot

 

certbotコマンドでバージョンを確認します。

 # certbot --version

--
certbot 1.13.0
--

 

3-4. Let’s Encrypt証明書取得のためのApache/Nginxの設定

要件の、

  • Webサイトのダウンタイムが(ほぼ)生じないよう、更新時に、Apache, NginxなどのWebサーバーは停止せず、更新後の再起動のみとする。
  • Let’s Encryptによる証明書取得または更新の認証アクセス時、Webコンテンツディレクトリにはアクセスさせない。

に従い、認証時はLet’s Encryptの「Webrootプラグイン」を使用して、ApacheもしくはNginxを起動したまま、Let’s Encyprtの認証サーバーから認証用ファイルにアクセスさせます。
また、認証用ファイルの設置箇所は、WebコンテンツディレクトリのDocumentRootとは別のディレクトリ(ここでは /var/www/certbot/ssltest2021.inaba-serverdesign.jp)とします。

Let’s Encyprt認証サーバーからの認証アクセスURLは
http://ssltest2021.inaba-serverdesign.jp/.well-know/acme-challenge/~
となるので、URLパス /.well-know/~ は、/var/www/certbot/ssltest2021.inaba-serverdesign.jp/.well-known/~ にアクセスさせるのがポイントです。

まず、認証用ファイルを設置するディレクトリを作成します。

 # mkdir -p /var/www/certbot/ssltest2021.inaba-serverdesign.jp

 

ApacheまたはNginxのConfigで設定を追記します。

・Apache 2.4の場合
ssltest2021.inaba-serverdesign.jp のVirtualHostセクションに追記します。

 # vim /etc/httpd/conf.d/ssltest2021.inaba-serverdesign.jp.conf

--
<VirtualHost *:80>
    DocumentRoot /var/www/ssltest2021.inaba-serverdesign.jp/public_html
    ServerName ssltest2021.inaba-serverdesign.jp
...

    # for Let's Encrypt
    Alias /.well-known /var/www/certbot/ssltest2021.inaba-serverdesign.jp/.well-known

    <Directory /var/www/certbot/ssltest2021.inaba-serverdesign.jp>
        Require all granted
    </Directory>
</VirtualHost>
--

 

Apache Configファイルの文法チェックを行ったうえで、ApacheサービスをreloadしてApacheに反映します。

 # apachectl -t
 # systemctl reload httpd

 

・Nginxの場合
ssltest2021.inaba-serverdesign.jp のserverセクションに追記します。

 # vim /etc/nginx/conf.d/ssltest2021.inaba-serverdesign.jp.conf

--
server {
    listen       80;

    server_name ssltest2021.inaba-serverdesign.jp;
    root   /var/www/ssltest2021.inaba-serverdesign.jp/public_html;
...

    # for Let's Encrypt
    location ^~ /.well-known/ {
        root /var/www/certbot/ssltest2021.inaba-serverdesign.jp;
    }
--

 

Nginx Configファイルの文法チェックを行ったうえで、NginxサービスをreloadしてNginxに反映します。

 # nginx -t
 # systemctl reload nginx

 

なお、ネット上では、Nginxの設定で以下を記載する例が多くみられます。

    location = /.well-known/acme-challenge/ {
        return 404;
    }

 

これは、
「http(s)://<domain>/.well-known/acme-challenge/(末尾は / で終了)でアクセスされたときに、ステータス404(Not Found)を返す」
という意味です。
ネット上の事例にあるコメントなどを見ると、
「第三者から不正アクセスされたときに、403(Forbidden)を返すより、404(Not Found)を返したほうが、存在を隠せるので、よりセキュアになる」
という意図があるようです。

ですが、(以前のバージョンはわかりませんが、少なくとも現在のcertbotコマンドでは)/.well-known ディレクトリは、Let’s Encryptの証明書を取得・更新するときのみ一時的に作成され、すぐに削除されるので、この設定がなくて403を返すのは、ほんの10秒間ぐらいで、それ以外のほとんどの時間帯はもともと404を返します。

ですので、無駄な設定とまでは言いませんが、
「存在を知られたくないURLパスへのアクセスに対しては404を返す」
というポリシーを貫くならば、管理画面やphpMyAdminなどの管理機能のURLパスにも同様の設定を行って統一すべきでしょう。

3-5. Let’s Encrypt証明書の取得

certbotコマンドのサブコマンド certonly で、証明書を取得します。
オプションについて補足します。

  • --webroot: Apache/Nginxを起動したままの認証とする。
  • -w: 認証時の Documentroot を指定。
  • -d: ドメインを指定。
  • --preferred-challenges: 認証方式を指定する。ここではHTTP認証とする。
  • --agree-tos: 利用規約の同意し、確認画面を表示しない。
  • -m: Let’s Encryptに登録するメールアドレス。登録したくなければ、代わりに --register-unsafely-without-email を指定すればよい。

※複数ドメインに対応した1枚の証明書を取得するときは、-w, -dを繰り返して、ドメインとDocumentRootのペアを追記します。

証明書の取得にどれくらい時間がかかるか知りたい場合は、Linuxのtimeコマンドをつけて実行するとよいでしょう。

 # time /usr/bin/certbot certonly \
    --webroot \
    -w /var/www/certbot/ssltest2021.inaba-serverdesign.jp \
    -d ssltest2021.inaba-serverdesign.jp \
    --preferred-challenges http \
    --agree-tos \
    -m <登録するメールアドレス>

--
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y  // メールアドレスの登録確認なので、y を入力


Account registered.
Requesting a certificate for ssltest2021.inaba-serverdesign.jp
Performing the following challenges:
http-01 challenge for ssltest2021.inaba-serverdesign.jp
Using the webroot path /var/www/certbot/ssltest2021.inaba-serverdesign.jp for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Subscribe to the EFF mailing list (email: ina128@inaba-serverdesign.jp).

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/privkey.pem
   Your certificate will expire on 2021-06-28. To obtain a new or
   tweaked version of this certificate in the future, simply run
   certbot again. To non-interactively renew *all* of your
   certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le


real    0m24.803s
user    0m0.926s
sys     0m0.077s

 

「- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem
Your key file has been saved at: ~」
と出力されれば、証明書の取得は成功です。
失敗した場合は、エラーメッセージや、デバッグログ /var/log/letsencrypt/letsencrypt.log を参照して、不具合箇所を調査、解消します。

発行された証明書ファイル群を確認します。

 # ls -l /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/

--
-rw-r--r-- 1 root root 692  3月 30 13:40 README
lrwxrwxrwx 1 root root  57  3月 30 13:40 cert.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/cert1.pem
lrwxrwxrwx 1 root root  58  3月 30 13:40 chain.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/chain1.pem
lrwxrwxrwx 1 root root  62  3月 30 13:40 fullchain.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/fullchain1.pem
lrwxrwxrwx 1 root root  60  3月 30 13:40 privkey.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/privkey1.pem
--

 

  • 証明書: /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/cert.pem
  • 秘密鍵: /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/privkey.pem
  • 中間証明書: /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/chain.pem
  • 証明書+中間証明書: /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem

証明書の内容は、opensslコマンドで確認できます。

 # openssl x509 -text -noout -in /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/cert.pem

--
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            04:fc:d2:68:51:8b:c4:d7:35:c3:14:ef:7e:ce:33:c1:57:15
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Let's Encrypt, CN=R3
        Validity
            Not Before: Mar 30 03:40:38 2021 GMT
            Not After : Jun 28 03:40:38 2021 GMT
        Subject: CN=ssltest2021.inaba-serverdesign.jp
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
...

            X509v3 Subject Alternative Name:
                DNS:ssltest2021.inaba-serverdesign.jp
...
--

 

Not Before(発行日)、Not After(有効期限)、CN(Common Name)、DNS(Alternative Name)などを確認します。

3-6. Apache/NginxのHTTPS設定

・Apache 2.4の場合
ssltest2021.inaba-serverdesign.jp のTCP/443のVirtualHostセクション内で、証明書、秘密鍵、中間証明書として、Let’s Encryptで取得した各ファイルを指定します。

 # vim /etc/httpd/conf.d/ssl_ssltest2021.inaba-serverdesign.jp.conf

--
<VirtualHost *:443>
    DocumentRoot /var/www/ssltest2021.inaba-serverdesign.jp/public_html
    ServerName ssltest2021.inaba-serverdesign.jp
...
    <Directory /var/www/certbot/ssltest2021.inaba-serverdesign.jp>
        Require all granted
    </Directory>
...
    SSLCertificateFile /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/chain.pem
...
</VirtualHost>

 

Apache Configファイルの文法チェックを行ったうえで、Apacheサービスを再起動してApacheに反映します。

 # apachectl -t
 # systemctl restart httpd

 

・Nginxの場合
ssltest2021.inaba-serverdesign.jp のTCP/443のserverセクション内で、証明書+中間証明書、秘密鍵として、Let’s Encryptで取得した各ファイルを指定します。

 # vim /etc/nginx/conf.d/ssl_ssltest2021.inaba-serverdesign.jp.conf

--
server {
    listen      443 ssl http2;

    server_name ssltest2021.inaba-serverdesign.jp;
    root   /var/www/ssltest2021.inaba-serverdesign.jp/public_html;
...
    ssl_certificate      /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/privkey.pem;
...
}
--

 

Nginx Configファイルの文法チェックを行ったうえで、Nginxサービスを再起動してNginxに反映します。

 # nginx -t
 # systemctl restart nginx

 

・確認
Apache/Nginxの設定を反映したのち、WebブラウザでWebサイト(https://ssltest2021.inaba-serverdesign.jp/)にHTTPSでアクセスして、正しくページが表示されることを確認します。
また、Webブラウザの証明書情報を確認します。

3-7. Apache/Nginxの常時SSL設定

Webサイトを常時SSL化する場合は、HTTP用のTCP/80のセクションでリダイレクトの設定を行います。
Let’s Encryptの認証も、HTTPSにリダイレクトされて実施されるので、Let’s Encrypt認証用の設定を、HTTPS用のTCP/443のセクションに追記します。

・Apache 2.4の場合

 # vim /etc/httpd/conf.d/ssltest2021.inaba-serverdesign.jp.conf

<VirtualHost *:80>
...
    # Redirect to HTTPS
    RewriteEngine on
    RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
...
</VirtualHost>

 

 # vim /etc/httpd/conf.d/ssl_ssltest2021.inaba-serverdesign.jp.conf

--
<VirtualHost *:443>
...
    # for Let's Encrypt
  Alias /.well-known /var/www/certbot/ssltest2021.inaba-serverdesign.jp/.well-known
...
</VirtualHost>

 

Apache Configファイルの文法チェックを行ったうえで、ApacheサービスをreloadしてApacheに反映します。

 # apachectl -t
 # systemctl reload httpd

 

・Nginxの場合

 # vim /etc/nginx/conf.d/ssltest2021.inaba-serverdesign.jp.conf

--
server {
    listen       80;
...
    # Redirect to HTTPS
    return 301 https://$host$request_uri;
...

--

 

 # vim /etc/nginx/conf.d/ssl_ssltest2021.inaba-serverdesign.jp.conf

--
server {
    listen      443 ssl http2;
...
    # for Let's Encrypt
    location ^~ /.well-known/ {
        root /var/www/certbot/ssltest2021.inaba-serverdesign.jp;
    }
...
}
--

 

Nginx Configファイルの文法チェックを行ったうえで、NginxサービスをreloadしてNginxに反映します。

 # nginx -t
 # systemctl reload nginx

 

・確認
Apache/Nginxの設定を反映したのち、WebブラウザでWebサイト(http://ssltest2021.inaba-serverdesign.jp/)にHTTPでアクセスして、正しくHTTPSページにリダイレクトされることを確認します。

以上で、Let’s Encryptを利用したSSLサーバー証明書の取得と設定は完了です。

isd4. SSLサーバー証明書の自動更新設定

Let’s Encrypt証明書の有効期間は90日と限定されており、期限が切れる前に更新する必要があります。

※Let’s Encryptの証明書は、デフォルトでは、有効期限まで30日未満のときのみ更新可能です。有効期限まで30日以上のときは、コマンドを実行しても、証明書を更新しません。

毎回手作業で更新するのは手間がかかるので、自動更新する設定を行います。

証明書の更新、更新エラーが発生したときのアラートメール通知といった一連の処理をシェルスクリプトにまとめ、cronで定期的に実行するようにします。

(2021.8.11追記)
Snap版certbotをインストールすると、証明書の自動更新機能も併せてインストールされます。
以下の
「4-2. 自動更新スクリプトの設定」
「4-3. cronの定期実行設定」
の設定は不要ですので、読み飛ばして
「4-4. Snap版certbotの証明書自動更新機能」
「4-5. Snap版certbotの証明書自動更新機能(補足)」
をご参照ください。

「4-1. 証明書更新コマンドの確認」については、手動で更新したい場合のご参考まで。
(2021.8.11追記ここまで)

4-1. 証明書更新コマンドの確認

証明書の更新は、certbotコマンドのサブコマンド renew を使用します。
コマンドはこんな感じです。

 # /usr/bin/certbot renew \
    --post-hook "systemctl restart httpd"

 

オプションについて補足します。

  • --post-hook: 証明書の更新後に実行するコマンドを指定する。更新が必要なときのみ(=デフォルトでは有効期限まで30日未満のときのみ)実行される。一般的には、更新後の証明書を反映するための、Apache/Nginxを再起動するコマンドを指定する。
  • --pre-hook: 証明書の更新前に実行するコマンドを指定する。更新が必要なときのみ(=デフォルトでは有効期限まで30日未満のときのみ)実行される。
  • --dry-run: テスト実行する(いわゆるドライラン)。実際には証明書は更新しない。--pre-hook, --post-hookで指定したコマンドは実行される。このオプションはcertonlyサブコマンドでも使用できる。
  • --force-renewal: 有効期限までの日数に関わらず、強制的に証明書を更新する。ただし、一定期間内に更新できる回数には制限がある。

証明書を取得したときに比べると、全然少ないですね。
これは、certonlyサブコマンドで証明書を取得したときに、ドメインごとのConfigファイル /etc/letsencrypt/renewal/<ドメイン>.conf に、取得実行時のオプションが保存されており、renewサブコマンドによる更新実行時は、そのConfigを参照するからです。

Configファイルの内容は以下のような感じです。

 # view /etc/letsencrypt/renewal/ssltest2021.inaba-serverdesign.jp.conf

--
# renew_before_expiry = 30 days
version = 1.13.0
archive_dir = /etc/letsencrypt/archive/ssltest2021.inaba-serverdesign.jp
cert = /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/cert.pem
privkey = /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/privkey.pem
chain = /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/chain.pem
fullchain = /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
pref_challs = http-01,
authenticator = webroot
webroot_path = /var/www/certbot/ssltest2021.inaba-serverdesign.jp,
server = https://acme-v02.api.letsencrypt.org/directory
[[webroot_map]]
ssltest2021.inaba-serverdesign.jp = /var/www/certbot/ssltest2021.inaba-serverdesign.jp
--

 

認証方式や認証時の Documentroot などを変更したい場合は、このConfigファイルを修正すればよいです。

動作確認のため、--dry-runオプションをつけて、証明書の更新をテスト実行してみます。
このとき、--post-hookで指定した Apache もしくは nginx の再起動が発生しますので、ご注意ください。

・Apache 2.4の場合

 # /usr/bin/certbot renew \
    --post-hook "systemctl restart httpd" \
    --dry-run

 

・Nginxの場合

 # /usr/bin/certbot renew \
    --post-hook "systemctl restart nginx" \
    --dry-run

 

以下のように、「Congratulations, all simulated renewals succeeded:」が出力されればOKです。

--
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/ssltest2021.inaba-serverdesign.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator webroot, Installer None
Account registered.
Simulating renewal of an existing certificate for ssltest2021.inaba-serverdesign.jp
Performing the following challenges:
http-01 challenge for ssltest2021.inaba-serverdesign.jp
Using the webroot path /var/www/certbot/ssltest2021.inaba-serverdesign.jp for all unmatched domains.
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: systemctl restart httpd
--

 

4-2. 自動更新スクリプトの設定と動作確認

※(2021.8.11追記)Snap版certbotをインストールすると、証明書の自動更新機能も併せてインストールされますので、この項の設定は不要です。

証明書の更新、更新エラーが発生したときのアラートメール通知といった一連の処理を行うシェルスクリプトを設置します。

※cronエントリーに直接certbotコマンドを設定してもよいのですが、僕はコマンドの実行時刻をログに記録したいので、たいていは、cronエントリーにコマンドをそのままセットすることはなく、シェルスクリプトを用意して設定するようにしています。

WEBSERVER_RESTART_CMD で、--post-hookに渡す、Webサーバーソフトウェアを再起動するコマンドを指定しています。
ApacheではなくNginxの場合は、httpd を nginx に置き換えてください。

MAILTOでは、アラートメールの通知先アドレスを指定します。
また、サーバー側ではmailコマンドでインターネット上にメールが送信できることを前提としています。

Linuxサーバーのメール送信設定については、以下などを参考にしてください。

・Postfixによるメール送信設定 – 稲葉サーバーデザイン
https://inaba-serverdesign.jp/blog/20160620/postfix_send_mail.html

 # vim /root/bin/update_sslcert.sh
 
--
#!/bin/bash
#
CERTBOT_CMD=/usr/bin/certbot
WEBSERVER_RESTART_CMD="systemctl restart httpd"

MAILTO=<メール通知先アドレス>

echo "===== Update SSL Certfile ====="
echo "`date` Update SSL Certfile start"

# 証明書の更新
${CERTBOT_CMD} renew \
  --post-hook "${WEBSERVER_RESTART_CMD}"

LE_STATUS=$?

# 証明書の取得に失敗したときはメールで通知
if [ "$LE_STATUS" != 0 ]; then
    echo "Update SSL Certfile failed" |\
    mail -s "Update SSL Certfile in `hostname`" ${MAILTO}
fi

echo "`date` Update SSL Certfile end"

# EOF
--

 

実行権限を付与します。

 # chmod 755 /root/bin/update_sslcert.sh

 

続いて、このシェルスクリプトの動作確認を行います。

シェルスクリプトを実行する前に、renewコマンドでは、証明書は有効期限まで残り30日未満にならないと更新されないため、強制的に更新するよう、--force-renewalオプションを追加します。

 # vim /root/bin/update_sslcert.sh

-- 変更前
...

${CERTBOT_CMD} renew \
  --post-hook "${WEBSERVER_RESTART_CMD}"
--

-- 変更後
...

${CERTBOT_CMD} renew \
  --post-hook "${WEBSERVER_RESTART_CMD}" --force-renewal
--

 

シェルスクリプトを実行します。

「Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem (success)」
のように成功したメッセージが出力されればOKです。

 # /root/bin/update_sslcert.sh

--
===== Update SSL Certfile =====
2021年  3月 30日 火曜日 15:39:25 JST Update SSL Certfile start
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/ssltest2021.inaba-serverdesign.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate for ssltest2021.inaba-serverdesign.jp

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded:
  /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: systemctl restart httpd
2021年  3月 30日 火曜日 15:39:32 JST Update SSL Certfile end
--

 

WebブラウザでWebサイト(https://ssltest2021.inaba-serverdesign.jp/)にアクセスして、正しくページが表示されることを確認します。
また、Webブラウザの証明書情報を確認します。

Apache(もしくはNginx)プロセスが再起動されたことを、psコマンドおよびApacheのエラーログで確認します。

 # ps aux | grep httpd

--
root     18252  0.1  0.7 227340  7284 ?        Ss   15:39   0:00 /usr/sbin/http  -DFOREGROUND
apache   18253  0.0  0.3 227340  3460 ?        S    15:39   0:00 /usr/sbin/http  -DFOREGROUND
apache   18254  0.0  0.3 227340  3460 ?        S    15:39   0:00 /usr/sbin/http  -DFOREGROUND
apache   18255  0.0  0.3 227340  3460 ?        S    15:39   0:00 /usr/sbin/http  -DFOREGROUND
apache   18256  0.0  0.3 227340  3460 ?        S    15:39   0:00 /usr/sbin/http  -DFOREGROUND
apache   18257  0.0  0.3 227340  3460 ?        S    15:39   0:00 /usr/sbin/http  -DFOREGROUND
root     18270  0.0  0.0 112824   976 pts/1    R+   15:40   0:00 grep --color=auto httpd
--

 # less /var/log/httpd/error_log

--
[Tue Mar 30 15:39:31.288950 2021] [mpm_prefork:notice] [pid 18202] AH00170: caught SIGWINCH, shutting down gracefully
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::862:14ff:fe69:f2d1. Set the 'ServerName' directive globally to suppress this message
[Tue Mar 30 15:39:32.390848 2021] [lbmethod_heartbeat:notice] [pid 18252] AH02282: No slotmem from mod_heartmonitor
[Tue Mar 30 15:39:32.393584 2021] [mpm_prefork:notice] [pid 18252] AH00163: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips configured -- resuming normal operations
[Tue Mar 30 15:39:32.393612 2021] [core:notice] [pid 18252] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'
--

 

証明書ファイルが更新されたことを確認します。
証明書ファイル群へのシンボリックリンク先ファイル名の世代数が、1から2に変わったことがわかります。
また、シンボリックリンクのタイムスタンプも更新実行時となっています。

 # ls -l /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/

--
-rw-r--r-- 1 root root 692  3月 30 13:40 README
lrwxrwxrwx 1 root root  57  3月 30 15:39 cert.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/cert2.pem
lrwxrwxrwx 1 root root  58  3月 30 15:39 chain.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/chain2.pem
lrwxrwxrwx 1 root root  62  3月 30 15:39 fullchain.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/fullchain2.pem
lrwxrwxrwx 1 root root  60  3月 30 15:39 privkey.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/privkey2.pem
--

 

4-3. cronの定期実行設定

※(2021.8.11追記)Snap版certbotをインストールすると、証明書の自動更新機能も併せてインストールされますので、この項の設定は不要です。

証明書を自動更新するシェルスクリプトを定期実行するよう、rootユーザーのcronエントリーに追加します。
ここでは、毎週月曜の5:00に自動更新を試みるよう設定します。
標準出力、標準エラー出力を /var/log/update_sslcert.log に書き出すようにするのがポイントです。

※有効期限が残り30日以上で証明書を更新しないときなど、更新エラーではないときも標準エラー出力に出力することがあるので、標準エラー出力のログも記録したほうがよいです。

 # crontab -e

--
# Update SSL Cert File
0 5 * * mon /root/bin/update_sslcert.sh 1>> /var/log/update_sslcert.log 2>&1
--

 

シェルスクリプト単体では正しく動作するのに、cronから実行したときはうまくいかない、ということも多いので、cronに追加したエントリーは必ずテスト実行しましょう。

3分後に実施するよう設定してみます。

 # crontab -e

--
# Update SSL Cert File
0 5 * * mon /root/bin/update_sslcert.sh 1>> /var/log/update_sslcert.log 2>&1
45 15 * * * /root/bin/update_sslcert.sh 1>> /var/log/update_sslcert.log 2>&1
--

 

cronで設定した時刻が過ぎるのを待ち(ランダムディレイにより、更新処理が数分かかる場合があります)、WebブラウザでWebサイト(https://ssltest2021.inaba-serverdesign.jp/)にアクセスして、正しくページが表示されることを確認します。
また、Webブラウザの証明書情報を確認します。

Apache(もしくはNginx)プロセスが再起動されたことを、psコマンドおよびApacheのエラーログで確認します。

 # ps aux | grep httpd

--
root     18347  0.1  0.7 227340  7284 ?        Ss   15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18348  0.0  0.3 227340  3460 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18349  0.0  0.3 227340  3460 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18350  0.0  0.3 227340  3460 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18351  0.0  0.3 227472  3952 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18352  0.0  0.5 227476  5220 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18357  0.0  0.3 227340  3460 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18358  0.0  0.3 227340  3460 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
apache   18359  0.0  0.3 227340  3460 ?        S    15:51   0:00 /usr/sbin/http  -DFOREGROUND
root     18361  0.0  0.0 112824   976 pts/1    R+   15:51   0:00 grep --color=auto httpd
--

 # less /var/log/httpd/error_log

--
[Tue Mar 30 15:51:23.424772 2021] [mpm_prefork:notice] [pid 18252] AH00170: caught SIGWINCH, shutting down gracefully
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::862:14ff:fe69:f2d1. Set the 'ServerName' directive globally to suppress this message
[Tue Mar 30 15:51:24.502161 2021] [lbmethod_heartbeat:notice] [pid 18347] AH02282: No slotmem from mod_heartmonitor
[Tue Mar 30 15:51:24.504959 2021] [mpm_prefork:notice] [pid 18347] AH00163: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips configured -- resuming normal operations
[Tue Mar 30 15:51:24.504986 2021] [core:notice] [pid 18347] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'
--

 

証明書ファイルが更新されたことを確認します。
証明書ファイル群へのシンボリックリンク先ファイル名の世代数が、2から3に変わったことがわかります。
また、シンボリックリンクのタイムスタンプも更新実行時となっています。

 # ls -l /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/

--
-rw-r--r-- 1 root root 692  3月 30 13:40 README
lrwxrwxrwx 1 root root  57  3月 30 15:51 cert.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/cert3.pem
lrwxrwxrwx 1 root root  58  3月 30 15:51 chain.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/chain3.pem
lrwxrwxrwx 1 root root  62  3月 30 15:51 fullchain.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/fullchain3.pem
lrwxrwxrwx 1 root root  60  3月 30 15:51 privkey.pem -> ../../archive/ssltest2021.inaba-serverdesign.jp/privkey3.pem
--

 

ログを確認します。

 # less /var/log/update_sslcert.log

--
===== Update SSL Certfile =====
2021年  3月 30日 火曜日 15:45:01 JST Update SSL Certfile start
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/ssltest2021.inaba-serverdesign.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Non-interactive renewal: random delay of 376.90223893085476 seconds
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate for ssltest2021.inaba-serverdesign.jp

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded:
  /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: systemctl restart httpd
2021年  3月 30日 火曜日 15:51:24 JST Update SSL Certfile end
--

 

動作確認が問題なければ、cronのテスト実行用エントリーを削除します。

 # crontab -e

--
# Update SSL Cert File
0 5 * * mon /root/bin/update_sslcert.sh 1>> /var/log/update_sslcert.log 2>&1
--

 

また、自動更新シェルスクリプトの強制更新オプション --force-renewal を削除します。

 # vim /root/bin/update_sslcert.sh

-- 変更前
...

${CERTBOT_CMD} renew \
  --post-hook "${WEBSERVER_RESTART_CMD}" --force-renewal
--

-- 変更後
...

${CERTBOT_CMD} renew \
  --post-hook "${WEBSERVER_RESTART_CMD}"
--

 

4-4. Snap版certbotの証明書自動更新機能

※この項は、2021.4.9 に追記し、2021.8.11に再度修正しました。

Snap版certbotをインストールすると、証明書自動更新機能も合わせてインストールされます。
CentOS 7であれば、systemdのタイマー機能として設定されます。
(僕は気づいていなかったのですが、EPEL版certbotでも、同様の certbot-renew.timer が含まれていたようです。)

 # systemctl list-timers | less

NEXT                         LEFT          LAST                         PASSED       UNIT                         ACTIVATES
金 2021-04-09 18:53:31 JST  1h 40min left 木 2021-04-08 18:53:31 JST  22h ago      systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
土 2021-04-10 02:55:00 JST  9h left       金 2021-04-09 15:56:01 JST  1h 17min ago snap.certbot.renew.timer     snap.certbot.renew.service

 

snap.certbot.renew.timer が登録されていますね。
snap.certbot.renew.timer のユニットファイルを確認します。

 # view /etc/systemd/system/snap.certbot.renew.timer

--
[Unit]
# Auto-generated, DO NOT EDIT
Description=Timer renew for snap application certbot.renew
Requires=var-lib-snapd-snap-certbot-1093.mount
After=var-lib-snapd-snap-certbot-1093.mount
X-Snappy=yes

[Timer]
Unit=snap.certbot.renew.service
OnCalendar=*-*-* 02:55
OnCalendar=*-*-* 15:56

[Install]
WantedBy=timers.target
--

 

snap.certbot.renew.serviceのユニットファイルを確認します。

 # view /etc/systemd/system/snap.certbot.renew.service

--
[Unit]
# Auto-generated, DO NOT EDIT
Description=Service for snap application certbot.renew
Requires=var-lib-snapd-snap-certbot-1093.mount
Wants=network.target
After=var-lib-snapd-snap-certbot-1093.mount network.target snapd.apparmor.service
X-Snappy=yes

[Service]
EnvironmentFile=-/etc/environment
ExecStart=/usr/bin/snap run --timer="00:00~24:00/2" certbot.renew
SyslogIdentifier=certbot.renew
Restart=no
WorkingDirectory=/var/snap/certbot/1093
TimeoutStopSec=30
Type=oneshot

[Install]
WantedBy=multi-user.target
--

 

ExecStart行の
/usr/bin/snap run --timer=”00:00~24:00/2″ certbot.renew
が、証明書を更新するコマンドのようです。

ただし、この機能では、証明書を使用するWebサーバーソフトウェアの再起動は行われません。
このため、更新後に自動的に実行されるスクリプトを自分で設定します。
以下はWebサーバーソフトウェアがNginxの場合の設定ですが、Apacheであれば、nginx を httpd に置き換えてください。

 # vim /etc/letsencrypt/renewal-hooks/post/web_restart.sh

--
#!/bin/bash
systemctl restart nginx
--

 # chmod 755 /etc/letsencrypt/renewal-hooks/post/web_restart.sh

 

このSnap版certbotの証明書自動更新機能を使用する場合は、4-1.から4-3.で記載した設定手順は不要です。
タイマー設定 /etc/systemd/system/snap.certbot.renew.timer によれば、OnCalenderパラメータで指定されていた毎日2時55分と15時56分に更新を試みます。

※2時55分、15時56分という時刻については、certbotのインストール時にランダムで決まるようです。また、certbotが自動アップデートされる度に、この時刻が変わります。

以上で、Let’s EncryptによるSSLサーバー証明書の取得、自動更新設定は完了です。

4-5. Snap版certbotの証明書自動更新機能(補足)

※この項は、2021.8.11 に追記しました。

Snap版certbotの運用を数ヶ月続けていて、以下の気になることがありました。

  1. 証明書の自動更新を実行する時刻がランダムである。
  2. 1. のせいで、好ましくない時間帯にWebサーバーソフトウェアの再起動が発生し、処理中のリクエストが強制終了される。

2. の、証明書の更新直後にで処理中のリクエストが強制終了され得ることについては、Snap版certbotとは関係なく、以前から存在していた問題です。
この影響をできるだけ少なくするため、certbot renewコマンドを利用した証明書の自動更新は、稼働しているサービスへのアクセスが少ない深夜早朝に実行するよう、cronでスケジューリングしていたわけです。

この問題については、ApacheやNginxであれば、restart ではなく、graceful restart(緩やかな再起動)を使用すれば、処理中のリクエストが終了してからプロセスの再起動が実行されるため、改善されます。

Systemd であれば、「systemctl reload nginx/httpd」コマンドを使用することで、graceful restart となります。

 # vim /etc/letsencrypt/renewal-hooks/post/web_restart.sh

--
#!/bin/bash
systemctl reload nginx
--

 

※systemctl reload ~ コマンドで実際には何が実行されるかは、Systemd ユニットファイルの ExcelReload 行で確認できます。/usr/lib/systemd/system/nginx.service, /usr/lib/systemd/system/httpd.service を参照してみるとよいでしょう。

また、1. の更新実行時刻の制御については、certbotのインストール後に /etc/systemd/system/snap.certbot.renew.timer で、希望する時刻に変更したとしても、Snapによりcertbotが自動アップデートされると、自動的に時刻が書き換わってしまいます。(たぶん)

このことで困っている人は他にもいるはず、と思って調べてみると、ありました。

・How do I schedule the Let’s Encrypt certbot to automatically renew just after hours? – Let’s Encrypt Community
https://community.letsencrypt.org/t/how-do-i-schedule-the-lets-encrypt-certbot-to-automatically-renew-just-after-hours/123861

このやりとりの中で
「You get to pick when to restart services, which doesn’t have to be synchronized with certificate updates in any way.」
という言葉があって、要は、
「証明書の更新と一緒にサービスを再起動する必要はない。
 サービスの再起動は、好きなタイミングにやればよい。」
ということですね。

確かに!!

このしくみでは、証明書は有効期限が30日未満(ほぼ29日)となったときに更新されるので、あとは、古い証明書の有効期限が切れる残り29日以内に、自分の好きなタイミングでApache/NginxなどのWebサーバーソフトウェアを再起動すればよいのです。

例えば、CentOS 7,8で、「yum install httpd」でApacheをインストールして、ログローテート設定をそのまま使えば、週に一度、ログローテート時に
「systemctl reload httpd (=graceful restart)」
が実行され、新しい証明書が反映されます。
この場合は、certbot renewal-hooks/post のスクリプト設定をしなくてもよいでしょう。

心配なら、cronで、「日曜の午前5時」など、お好みのタイミングで「systemctl reload nginx/httpd」するようスケジューリング設定してもよいですし。

 # crontab -e

--
# Graceful Restart Nginx for Update SSL Certfile
0 5 * * 0 systemctl reload nginx 1>> /var/log/update_sslcert.log 2>&1
--

 

どうしても「証明書更新後に、新しい証明書をできるだけ早く反映したい」ということであれば、certbot renewal-hooks/post に設定するスクリプトにおいて、以下のように atコマンドでお好きな時刻を指定して、一度だけ再起動を実行するよう設定するとよいでしょう。
(動作確認済み。)

 # vim /etc/letsencrypt/renewal-hooks/post/web_restart.sh

--
#!/bin/bash
echo "systemctl reload nginx" | at "5:00"
--

 

atdが起動していないと動作しませんので、インストール確認と起動確認をお忘れなく。

 # yum install atd

 # systemctl enable --now atd

 # systemctl status atd

 

なお、renewal-hooks 以下に設定したスクリプトは、証明書を更新するタイミング=ほぼ2ヶ月に一度しか動作しません。
できるだけ早く動作確認したいときは、ドメインごとのConfigファイル /etc/letsencrypt/renewal/<ドメイン>.conf で renew_before_expiry = 30 の数字を増やせば、早く確認できます。

以下のようにすれば、snap.certbot.renew.timer による毎日2回の証明書更新試行時に、証明書の有効期限が85日未満であれば、証明書が更新されます。

 # vim /etc/letsencrypt/renewal/<ドメイン>.conf

--
# renew_before_expiry = 30
renew_before_expiry = 85
--

 

isd5. Snap版certbotについて補足

Snap版certbotについて補足します。

  • Snap版certbotについて
  • DNS認証プラグインのインストール

Snap版certbotについて

2021年1月にリリースされた certbot 1.11.0 より、従来の certbot-auto は非推奨となり、代わりに、Snap版certbot が推奨となりました。

Snap (Snappy) は、ソフトウェアパッケージ管理システムです。

・Snappy (Wikipedia)
https://ja.wikipedia.org/wiki/Snappy

Snapのソフトウェアは、OS上の既存のソフトウェアに全く依存しない形で配布されます。

以下の記事に、Let’s Encryptがcertbot-autoを非推奨として、Snap版certbotを推奨することになった経緯が書かれています。

・Certbot-auto no longer works on Debian based systems, What happened? – Let’s Encrypt
https://community.letsencrypt.org/t/certbot-auto-no-longer-works-on-debian-based-systems/139702/7

簡単に言えば、
「Pythonの依存関係をcertbot-autoコマンドのみで解決することが難しくなった」
ということで、これを解決するには、Snapのような、他のパッケージに依存しない形でのソフトウェア配布が望ましい、ということでしょう。

このため、Snap版certbotは、従来のcertbot-autoのように、インストール時や更新時に、ApacheやPython等のソフトウェアパッケージを勝手にアップデートすることはなく、また、依存関係でエラーとなることもありません。
これはメリットといえますね。

ディメリットとしては、certbot-auto よりもディスク、メモリリソースを使用する、という点があります。
ディスク使用量にOS上にある他のライブラリやモジュールを一切使用しないということで、インストールパッケージが大きくなります。
その分、ダウンロードするファイルサイズ合計が大きいため、インストールにも少し時間がかかります。

ディスクは、Snap全体では876MB、certbotだけでも172MB使用していることがわかります。

 # du -hs /var/lib/snapd/

--
876M    /var/lib/snapd/
--

 # du -hs /var/lib/snapd/snap/certbot/

--
172M    /var/lib/snapd/snap/certbot/
--

 

(2021.8.11追記)
Snap版certbotをインストールしてからしばらく経つと、Snap全体のディスク使用量はさらに増えて、1.9GBとなりました。

 # du -hs /var/lib/snapd/

--
1.9G    /var/lib/snapd/
--

 

これは、Snapの仕様で、Snapが管理するソフトウェアパッケージは、最低2世代はバージョンを保存するためです。
保存されているソフトウェアパッケージとバージョンの一覧は、以下のコマンドで確認できます。

 # snap list --all

--
Name     Version    Rev    Tracking       Publisher     Notes
certbot  1.17.0     1280   latest/stable  certbot-eff?  disabled,classic
certbot  1.18.0     1343   latest/stable  certbot-eff?  classic
core     16-2.51.1  11316  latest/stable  canonical?    core,disabled
core     16-2.51.3  11420  latest/stable  canonical?    core
core20   20210429   1026   latest/stable  canonical?    base,disabled
core20   20210702   1081   latest/stable  canonical?    base
--

 

(2021.8.11追記ここまで)

メモリ使用量が増えるのは、snapdを常駐させる分です。
いくつかのサーバーで比べてみると少し幅があって、12~32MBぐらいでした。

 # ps aux | grep snapd
root     18977  0.6  2.4 917272 24548 ?        Ssl  18:31   0:00 /usr/libexec/snapd/snapd

 

ディスクやメモリが潤沢なサーバーであれば全く気にしなくてもよいレベルでしょうが、AWS EC2でいえば、メモリ512MBの t3.nano を、デフォルトのディスクサイズ8GBで使用しているような最小スペックの場合は、少し注意が必要でしょう。

ちなみに、snapd を停止すると、certbotコマンドの実行がエラーしますので、起動したままとしましょう。

 # systemctl stop snapd.socket

 # certbot --version

--
An error occurred while fetching Certbot snap plugins: make sure the snapd service is running.
An unexpected error occurred:
requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionRefusedError(111, 'Connection refused'))
Please see the logfile '/tmp/tmpjq5uj9hz/log' for more details.
--

 

他にちょっと気になるのは、設定手順のところにも書きましたが、snap install, refreshコマンドがときどきエラーとなることです。
比較的新しい技術だから?なのか、CentOSだけなのか、僕の環境だけなのか、よくわかりませんが、Chef, Ansibleなどで自動インストールする場合は、エラーすることも踏まえて、インストールが完了するよう工夫する必要があるでしょう。

DNS認証プラグインのインストール

Let’s Encryptの証明書を、DNSサービスと連携、自動認証して取得・更新する場合は、以下にDNSプラグインのインストール手順が記載されています。
(「wildcard」タブのほうです。)

・certbot instructions, None of the above on CentOS/RHEL 7, wildcard
https://certbot.eff.org/lets-encrypt/centosrhel7-other#wildcard

snap install --classic certbot コマンドでcertbotをインストールしたあと、以下のコマンドを実行して、プラグインをインストールします。
<PLUGIN> のところは、DNSサービスに応じて置き換えます。

 # snap set certbot trust-plugin-with-root=ok

 # snap install certbot-dns-<PLUGIN>

 

例えば、DNSサービスとして、AWS Route53 を使用しているなら、certbot-dns-route53プラグインをインストールします。

 # snap install certbot-dns-route53

 

これで、例えば以下のようにして、DNS認証で証明書を取得できます。
(コマンド実行には、Route 53へのアクセス権限が必要です。)

 # time /usr/bin/certbot certonly \
    --dns-route53 --dns-route53-propagation-seconds 30 \
    -d ssltest2021.inaba-serverdesign.jp \
    --agree-tos \
    -m <登録するメールアドレス>

 

isd6. Let’s Encrypt証明書の運用で気になること

Let’s Encrypt証明書の設定、自動更新の運用で気になっていることについて、いくつかコメントします。

  • Android 7.1以前の端末への対応
  • 証明書有効期限の監視
  • メールアドレスの登録は必要?
  • 1サーバーで複数ドメインの証明書を運用する場合
  • サーバー証明書の削除
  • renewコマンドの--pre-hook, --post-hook, --deploy-hookオプション

Android 7.1以前の端末への対応

2020年ごろから
「ルート証明書の変更により、近々、Android 7.1以前の端末ではLet’s Encrypt証明書のサイトが見れなくなる」
という話題がありました。

結論からいうと、Let’s Encyrpt側の対応で、2024年初頭まではこの問題が発生しないよう、先延ばしされました。
そして、2024年初頭の時点では、Android 7.1以前の端末は、もうサポートする必要がないでしょう。
詳しくは、Let’s Encyptの以下の記事を参照してください。

・Extending Android Device Compatibility for Let’s Encrypt Certificates – Let’s Encrypt
https://letsencrypt.org/2020/12/21/extending-android-compatibility.html

「この問題に対応したクロスサインの中間証明書がデフォルトで発行されるようになる」
と書かれていますので、僕の理解が正しければ、certbotコマンドで証明書を取得・更新しているユーザーは、とくに何も対処しなくてよいはずです。
証明書の取得・更新時に
「--preferred-chain “DST Root CA X3” オプションをつけるとよい」
という話題もありましたが、Let’s Encyrpt側の対応により、このオプションも不要となったはずです。

証明書有効期限の監視

「いつの間にか証明書の期限が切れていて、あわてて更新する」という話はわりとよく聞きます。
Webサイトを多数運用していると、証明書の管理が大変ですよね。

「Let’s Encryptで自動更新設定をしたので大丈夫!」と思われそうですが、Let’s Encryptでも、Let’s Encrypt側サーバーの問題、Apache/Nginxの設定ミス、アクセス制限の設定間違い等で、更新に失敗することがあり得ます。

※Snap版certobotにより、パッケージの依存関係によるエラーはなくなります。

そういったこともあり、Let’s Encryptに限りませんが、証明書の有効期限は、監視ツールで監視すべきだと思います。
僕は、Nagios check_httpプラグインで、証明書の有効期限をチェックし、残り20日以内となったときはアラート通知するようにしています。
Zabbixや、Webサイト監視サービスでも、同様の機能がありますね。

(参考)
・NagiosでSSLサーバー証明書の有効期限を監視 – 稲葉サーバーデザイン
https://inaba-serverdesign.jp/blog/20150825/nagios_ssl_certificate_sni.html

メールアドレスの登録は必要?

証明書取得時の、Let’s Encryptへのメールアドレス登録ですが、僕は余計なメールはあまり受け取りたくないので、1ドメインのみ登録して、それ以外は登録していません。

これまでLet’s Encryptからメールで届いた情報は、
「証明書の有効期限が間近」
「Agreement(利用規約)の変更)」
「認証方式 TLS-SNI-01 が廃止されるので、現在の設定を変更するように」
といったことぐらいでしょうか。

上記の最後のは重要ですが、それ以外は、自分で証明書有効期限の監視を行っていることもあり、あまり有用な情報ではありません。
例えば「ワイルドカードの証明書に対応しました」のような、便利な機能追加や、有用な仕様変更の情報を伝えてくれるとよいのですが、そういうメールはなかったように思います。。

1サーバーで複数ドメインの証明書を運用する場合

マルチホスティングのサーバーで、1つのサーバーで全く異なるドメインの複数の証明書(example.jp と example.com と example.co.jp など)を設置して運用するケースも多いと思います。

この場合、certbot renewコマンドによる更新時に、すべての証明書が更新されます。
certbotコマンドが、ドメインごとのConfigファイル /etc/letsencrypt/renewal/<ドメイン>.conf を探して、すべてのドメインに対して更新してくれるんですね。

もし、Webサイトの廃止などで、このサーバーで証明書を使用しなくなるときはcertbot revokeコマンドで証明書ファイル群を削除しないと、certbot renewコマンドが証明書の更新を試みてしまうので、注意しましょう。

証明書の削除

Webサイトの廃止、他サーバーへの移行などで、このサーバーで証明書を使用しなくなるときは、certbot revokeコマンドで証明書を失効させます。
また、--delete-after-revokeオプションをつけると、証明書の失効と合わせて、証明書ファイルが削除されます。

 # /usr/bin/certbot revoke \
   --cert-name ssltest2021.inaba-serverdesign.jp --delete-after-revoke

--
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificate(s) are selected for deletion:

  * ssltest2021.inaba-serverdesign.jp

Are you sure you want to delete the above certificate(s)?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y  // 削除してよいときは y を入力

Deleted all files relating to certificate ssltest2021.inaba-serverdesign.jp.
Congratulations! You have successfully revoked the certificate that was located at /etc/letsencrypt/live/ssltest2021.inaba-serverdesign.jp/cert.pem.
--

 

renewコマンドの--pre-hook, --post-hook, --deploy-hookオプション

renewコマンドには、--deploy-hookオプションもあります。
--pre-hook, --post-hookオプションで指定したコマンドは、証明書の更新を試みるとき(更新が成功しても失敗しても)に実行されます。
一方、--deploy-hookオプションで指定したコマンドは、証明書の更新が成功したときのみ実行されます。

ですので、「証明書の更新に失敗したときは、Apache/Nginxを再起動したくない」という場合は、--post-hookオプションの代わりに、--deploy-hookオプションを使用するとよいでしょう。

ただし、1サーバー上で複数ドメインの証明書を更新する場合、--post-hookオプションで指定したコマンドは、最後に一度だけ実行されるのに比べて、--deploy-hookオプションで指定したコマンドは、1つの証明書を更新するたびに、コマンドが実行されます。
例えば、3ドメインの証明書を運用し、--deploy-hookオプションでApacheの再起動コマンドを指定した場合、同じタイミングで3ドメインの証明書が更新されると、Apacheの再起動も3回実行されます。

ということもあり、個人的には、--post-hookオプションで十分かなと思っています。

isdおわりに

Let’s EncryptによるSSLサーバー証明書の取得、自動更新設定について、最近、certbotコマンドの推奨インストール方法が変わりましたので、2021年3月版としてまとめ直しました。

Snap版certbotコマンドを使用することで、OS上で、Pythonモジュールなど依存関係のあるソフトウェアパッケージが勝手にインストール、更新されることがなくなったことと、依存関係によるエラー発生がなくなることは、メリットといえるでしょう。

(関連記事)
・Let’s EncryptによるSSLサーバー証明書の取得、自動更新設定(Snapを使用しない版)
https://inaba-serverdesign.jp/blog/20211019/pip-lets-encrypt-ssl-certificate-update-html.html

・Postfixによるメール送信設定
https://inaba-serverdesign.jp/blog/20160620/postfix_send_mail.html

・NagiosでSSLサーバー証明書の有効期限を監視
https://inaba-serverdesign.jp/blog/20150825/nagios_ssl_certificate_sni.html

・Let’s EncryptによるSSLサーバー証明書の取得、自動更新設定(2019年1月版)
https://inaba-serverdesign.jp/blog/20190205/lets_encrypt_ssl_certificate_update.html

 

Follow me!