certbotでthe following renewal configurations were invalidが出た

吹き飛んだ家鯖の環境再構築の一環でcertbotを再設定し、証明書の更新テストを行ったところ「the following renewal configurations were invalid」なるエラーが発生した。

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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /usr/local/etc/letsencrypt/renewal/hoge.example.com-0001.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
(略)
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/usr/local/etc/letsencrypt/live/hoge.example.com-0001/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /usr/local/etc/letsencrypt/renewal/hoge.example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/certbot/_internal/renewal.py", line 70, in _reconstitute
    renewal_candidate = storage.RenewableCert(full_path, config)
  File "/usr/local/lib/python3.8/site-packages/certbot/_internal/storage.py", line 468, in __init__
    self._check_symlinks()
  File "/usr/local/lib/python3.8/site-packages/certbot/_internal/storage.py", line 538, in _check_symlinks
    raise errors.CertStorageError(
certbot.errors.CertStorageError: expected /usr/local/etc/letsencrypt/live/hoge.example.com/cert.pem to be a symlink
Renewal configuration file /usr/local/etc/letsencrypt/renewal/hoge.example.com.conf is broken. Skipping.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
  /usr/local/etc/letsencrypt/live/hoge.example.com-0001/fullchain.pem (success)

Additionally, the following renewal configurations were invalid:
  /usr/local/etc/letsencrypt/renewal/hoge.example.com.conf (parsefail)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0 renew failure(s), 1 parse failure(s)

んん-?confファイルのパースエラー?というのは早計で、実際のエラーはその上に書いてある「certbot.errors.CertStorageError: expected /usr/local/etc/letsencrypt/live/hoge.example.com/cert.pem to be a symlink」というやつ。

要は/usr/local/etc/letsencrypt/live/ドメイン/以下のpemファイルは、/usr/local/etc/letsencrypt/archive/ドメイン/のpemファイルへのシンボリックリンクじゃないとダメらしい。liveの方を確認してみたら、確かにシンボリックリンクではなく実ファイルになっていた。

root@example:/usr/local/etc/letsencrypt/live/hoge.example.com # ls -al
total 32
drwxr-xr-x  2 root  wheel     7 Dec 21 08:06 .
drwx------  4 root  wheel     5 May  4 10:36 ..
-rw-r--r--  1 root  wheel   692 Aug 17  2019 README
-rw-r--r--  1 root  wheel  1834 Dec 21 08:06 cert.pem
-rw-r--r--  1 root  wheel  1586 Dec 21 08:06 chain.pem
-rw-r--r--  1 root  wheel  3420 Dec 21 08:06 fullchain.pem
-rw-------  1 root  wheel  1704 Dec 21 08:06 privkey.pem

確かな原因は分からないけど、Boot Environment環境への移行作業でやらかした線が濃厚。

となれば、シンボリックリンクにすれば解決するハズなんだけど、これまた「OpenSSL.crypto.Error」とかいうエラーが発生してダメだった。

そもそも同一ドメインに対して、何で「hoge.example.com.conf」と「hoge.example.com-0001.conf」の2つの設定があるんだ?というか、どちらのconfファイルも作った覚えはない。

色々試してみるとcertbot certonlyコマンドで証明書を取得すると、対応するconfファイルが自動で作られるっぽい。で、同名ファイル(同名ドメイン)が存在する場合、連番付きのconfになる模様。

それならばconfファイルと証明書を全部消し、証明書取得からやり直したところ、無事更新まで通った。confファイル置き場は/usr/local/etc/letsencrypt/renewal/ね。

参考サイト