Let's Encrypt(certbot)でrenewしたら"expected /etc/letsencrypt/live/~/cert.pem"

このブログのSSLサーバ証明書発行で使用している Let's Encrypt
証明書の有効期限(90日間)が切れそうだったので、証明書の更新ついでにcertbot-autoのアップデートをかけたらタイトルのエラーが発生。
対応内容を備忘録として残しておきます。

certbot-auto のアップデート

certbot-autoのアップデートは、最新のcertbot-autoスクリプトファイルを取ってきて置き換えただけ。
この時の最新バージョンはv19.0.0でした。

$ wget https://dl.eff.org/certbot-auto
$ chmod a+x certbot-auto
$ mv ./certbot-auto /usr/local/bin

certbot-auto renew --dry-run 実行(失敗)

サーバ証明書の更新確認をするため、certbot-auto renew --dry-runを実行。

$ certbot-auto renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/kinformation.wjg.jp.conf
-------------------------------------------------------------------------------
expected /etc/letsencrypt/live/kinformation.wjg.jp/cert.pem to be a symlink
Renewal configuration file /etc/letsencrypt/renewal/kinformation.wjg.jp.conf is broken. Skipping.

-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

No renewals were attempted.

Additionally, the following renewal configuration files were invalid:
  /etc/letsencrypt/renewal/kinformation.wjg.jp.conf (parsefail)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
-------------------------------------------------------------------------------
0 renew failure(s), 1 parse failure(s)

と出て、チェック失敗となった。
原因はこのあたり?

expected /etc/letsencrypt/live/kinformation.wjg.jp/cert.pem to be a symlink
Renewal configuration file /etc/letsencrypt/renewal/kinformation.wjg.jp.conf is broken. Skipping.

設定ファイル確認

Renewal configuration file is broken.とか言ってるので、とりあえず設定ファイルを確認。

$ cat /etc/letsencrypt/renewal/kinformation.wjg.jp.conf
# renew_before_expiry = 30 days
version = 0.18.1
archive_dir = /etc/letsencrypt/archive/kinformation.wjg.jp
cert = /etc/letsencrypt/live/kinformation.wjg.jp/cert.pem
privkey = /etc/letsencrypt/live/kinformation.wjg.jp/privkey.pem
chain = /etc/letsencrypt/live/kinformation.wjg.jp/chain.pem
fullchain = /etc/letsencrypt/live/kinformation.wjg.jp/fullchain.pem

# Options used in the renewal process
[renewalparams]
authenticator = nginx
installer = nginx
account = *******

特に問題はなさそう。

/etc/letsencrypt/live を確認

expected /etc/letsencrypt/live/kinformation.wjg.jp/cert.pem to be a symlink
liveディレクトリのcert.pemがシムリンクじゃないと言っている。

$ ls -l /etc/letsencrypt/live/kinformation.wjg.jp/
合計 20
-rw-r--r-- 1 root root  543 10月 29 09:29 README
-rw-r--r-- 1 root root 1805 10月 29 09:29 cert.pem
-rw-r--r-- 1 root root 1647 10月 29 09:29 chain.pem
-rw-r--r-- 1 root root 3452 10月 29 09:29 fullchain.pem
-rw-r--r-- 1 root root 1704 10月 29 09:29 privkey.pem

確かに、実体ファイル。

じゃあ、どのファイルにリンク張られてるのが正しいの?

ggったら、以下のページが参考になった。

https://community.letsencrypt.org/t/error-with-letsencrypt-renew/13781/2

lrwxrwxrwx 1 root root 41 Apr 4 10:09 cert.pem -> ../../archive/dryg.org/cert2.pem
lrwxrwxrwx 1 root root 42 Apr 4 10:09 chain.pem -> ../../archive/dryg.org/chain2.pem
lrwxrwxrwx 1 root root 46 Apr 4 10:09 fullchain.pem -> ../../archive/dryg.org/fullchain2.pem
lrwxrwxrwx 1 root root 44 Apr 4 10:09 privkey.pem -> ../../archive/dryg.org/privkey2.pem

/archiveディレクトリ配下のファイルに向けてリンクを張るらしい。

/etc/letsencrypt/archive を確認

$ ls -l /etc/letsencrypt/archive/kinformation.wjg.jp/
合計 32
-rw-r--r-- 1 root root 1805 10月 29 09:29 cert1.pem
-rw-r--r-- 1 root root 1647 10月 29 09:29 chain1.pem
-rw-r--r-- 1 root root 3452 10月 29 09:29 fullchain1.pem
-rw-r--r-- 1 root root 1704 10月 29 09:29 privkey1.pem

/live配下のファイルと一致しているのか確認

$ ls -1 live/kinformation.wjg.jp/* | xargs md5sum
57df5a69b09e8e73cd4a3dd947bfa089  live/kinformation.wjg.jp/README
2df92c5ec4485d50dfd79d8bc5dc48b3  live/kinformation.wjg.jp/cert.pem
6a18b35b02d0b252d9342098265599c5  live/kinformation.wjg.jp/chain.pem
57b967ccf347db18d7b90258341c5ca3  live/kinformation.wjg.jp/fullchain.pem
5b3f7f6dedc3bd8711fe749834925a7f  live/kinformation.wjg.jp/privkey.pem

$ ls -1 archive/kinformation.wjg.jp/* | xargs md5sum
2df92c5ec4485d50dfd79d8bc5dc48b3  archive/kinformation.wjg.jp/cert1.pem
6a18b35b02d0b252d9342098265599c5  archive/kinformation.wjg.jp/chain1.pem
57b967ccf347db18d7b90258341c5ca3  archive/kinformation.wjg.jp/fullchain1.pem
5b3f7f6dedc3bd8711fe749834925a7f  archive/kinformation.wjg.jp/privkey1.pem

一緒っぽい。

リンクを張る

旧ディレクトリを退避

$ cd /etc/letsencrypt/live
$ cp -r kinformation.wjg.jp old_kinformation.wjg.jp

実体ファイル削除

$ rm -f kinformation.wjg.jp/*

それぞれリンクを張っていく

$ cd kinformation.wjg.jp

$ ln -s ../../archive/kinformation.wjg.jp/cert1.pem cert.pem
$ ln -s ../../archive/kinformation.wjg.jp/chain1.pem chain.pem
$ ln -s ../../archive/kinformation.wjg.jp/fullchain1.pem fullchain.pem
$ ln -s ../../archive/kinformation.wjg.jp/privkey1.pem privkey.pem

確認

$ ls -l
合計 0
lrwxrwxrwx 1 root root 43 11月 29 23:46 cert.pem -> ../../archive/kinformation.wjg.jp/cert1.pem
lrwxrwxrwx 1 root root 44 11月 29 23:46 chain.pem -> ../../archive/kinformation.wjg.jp/chain1.pem
lrwxrwxrwx 1 root root 48 11月 29 23:46 fullchain.pem -> ../../archive/kinformation.wjg.jp/fullchain1.pem
lrwxrwxrwx 1 root root 46 11月 29 23:47 privkey.pem -> ../../archive/kinformation.wjg.jp/privkey1.pem

再度、certbot-auto renew --dry-run 実行

$ certbot-auto renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/kinformation.wjg.jp.conf
-------------------------------------------------------------------------------
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator nginx, Installer nginx
Renewing an existing certificate
Performing the following challenges:
tls-sni-01 challenge for kinformation.wjg.jp
Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed with reload of nginx server; fullchain is
/etc/letsencrypt/live/kinformation.wjg.jp/fullchain.pem
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/kinformation.wjg.jp/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
-------------------------------------------------------------------------------

エラーなくドライランが完走しました。

certbot-auto renew 実行

certbot-auto renewを実行し、実際に証明書更新を実行。

$ certbot-auto renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/kinformation.wjg.jp.conf
-------------------------------------------------------------------------------
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator nginx, Installer nginx
Renewing an existing certificate
Performing the following challenges:
tls-sni-01 challenge for kinformation.wjg.jp
Waiting for verification...
Cleaning up challenges

-------------------------------------------------------------------------------
new certificate deployed with reload of nginx server; fullchain is
/etc/letsencrypt/live/kinformation.wjg.jp/fullchain.pem
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/kinformation.wjg.jp/fullchain.pem (success)
-------------------------------------------------------------------------------

無事成功し、証明書更新ができました。