Let’s Encryptの証明書自動更新(Mastodon)について備忘録

自分用備忘録でちゃんとした知識はないので諸々ご容赦ください。
また、記事(の下書き)を書いたのは2024年の11月頃なので、記事内の時空が壊れています。ご容赦ください。
前回の記事はこちら。

下書きまで書いて、あとは投稿ってところだったのにぬくぬく過ごしていたら、Let’s Encryptから「証明書更新してねメールが来なくなるよ!」みたいなメールが来ましたね……。
ちなみに先日証明書を確認したら、この記事に書いた内容で問題なく更新できていることが確認できました。
やったね!

証明書の自動更新ができていない!

タイトルの通り。なんか上手くいかず「期限切れまっせ!」みたいなメールが3か月おきくらいに届いてた。
5月くらい、8月くらい、10月の計3回かな?

恐らく1回目は、更新はできていたけどnginxの再起動をしていなくて反映されていなかった、とかだと思う。
覚えていないけど……。

2回目は、上記対策としてnginxを再起動するように設定したものの、その対策の何かが上手くいっていなくて更新ができていなかった、とかだと思う。
いろいろ調べてみたものの、よくわからず結局手で更新した?みたいだけど……。

そして今回、nginxの再起動自動化のために前々回追加したコマンドオプションが間違っていたことが原因であるとわかった。
恐らく2回目の時も同じ理由で更新できていなかったのだろう。
参考にしたサイトのコマンドの記載が間違っていたようで、特に考えずコピペしていたのがいけなかった。
自分の知識にないものをコピペをするときは、コピペするものがどういうものか調べてから使うようにしよう!(あたりまえ体操)

まず結論、今回の対応内容

ログ調査してコマンドがミスっていたことが分かったので、各ファイルを見直した。

certbot.timerファイルの見直し

デフォルトの記載なのか、どこかのサイトを見て設定したのかは覚えていないけど、記載内容は問題なさそうだった。
現状は下記の通り、毎日0時と12時に実行するような設定となっている。
RandomizedDelaySecでちょっと時間をずらしているようなので、確実に0時と12時に行われるわけではない。

[Unit]
Description=Run certbot twice daily

[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=43200
Persistent=true

[Install]
WantedBy=timers.target

ちなみに私の環境では/lib/systemd/system/certbot.timerにファイルがあった。
元からこの場所にあるのかは覚えていないけど、今パパっと調べてみた情報ではシステムデフォルトの場所かな……?

certbot.serviceファイルの見直し

続いて、serviceファイルの見直し。
今回はこちらのExecStartに記載していたコマンドをミスっていた。
certbot renewをする際の--post-hookオプションを-post-hookと記載していた。

今は下記の通りに修正し、ついでにpostからdeployに変えてみて、来年の2月の実行を待つ感じになった。
→ 2025年2月に確認したところ更新できていました!!

[Unit]
Description=Certbot
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
Documentation=https://certbot.eff.org/docs
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot -q renew --deploy-hook "systemctl reload nginx.service"
PrivateTmp=true

ちなみにこちらも私の環境では/lib/systemd/system/certbot.serviceにファイルがあった。

調査の流れ

割と試行錯誤していたので覚えている部分だけ記載。

期限確認

「期限切れまっせ」メールが来ていたので、鯖にアクセスして証明書を確認するも、有効期限が12月とか表示されて「切れてなくね?」となる。
ただ、よく見るとメインドメインの表記で記載されている。
どうやらサブドメインの更新期限はここからは見れないぽい。
いや、もしかしたら見る方法はあるのかもしれないけど、調べずに突き進んだ。
vpsに接続して、以下のように確認。

$ certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: XXXXX.com
    Serial Number: XXXXXXXXXXXXXXXXXXXXXXXXX
    Key Type: RSA
    Domains: *.XXXXX.com
    Expiry Date: 2024-10-31 16:28:43+00:00 (VALID: 1 day)
    Certificate Path: /etc/letsencrypt/live/XXXXX.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/XXXXX.com/privkey.pem
  Certificate Name: XXXXX.XXXXX.com
    Serial Number: XXXXXXXXXXXXXXXXXXXXXXXXX
    Key Type: RSA
    Domains: XXXXX.XXXXX.com
    Expiry Date: 2024-10-31 16:28:53+00:00 (VALID: 1 day)
    Certificate Path: /etc/letsencrypt/live/XXXXX.XXXXX.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/XXXXX.XXXXX.com/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ふ~ん、「VALID: 1 day」ね……………………いや、切れるじゃん!!!!となり、慌てて対応。

timer確認

まず、timerが動いているのかをチェック。

$ systemctl status certbot.timer
 ● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Wed 2024-10-30 14:57:41 JST; 1h 4min ago
    Trigger: Thu 2024-10-31 03:47:51 JST; 11h left
   Triggers: ● certbot.service

10月 30 14:57:41 XXXXXX systemd[1]: Started Run certbot twice daily.
$ systemctl list-timers
NEXT                        LEFT     LAST                        PASSED       UNIT          ACTIVATES
Thu 2024-10-31 08:37:03 JST 15h left Wed 2024-10-30 12:31:48 JST 4h 19min ago certbot.timer certbot.service

一部抜粋しているが、こんな感じで出力されて、動いてそうだなあとなる。

サービス?のログ確認

続いて、journalctlでログが見れるようなので、それを試してみる。

$ journalctl -ru certbot

すると、以下のようなのが出てきた。こちらも一部抜粋。

10月 30 12:31:49 ruse-vps systemd[1]: Failed to start Certbot.
10月 30 12:31:49 ruse-vps systemd[1]: certbot.service: Failed with result 'exit-code'.
10月 30 12:31:49 ruse-vps systemd[1]: certbot.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
10月 30 12:31:49 ruse-vps certbot[3046024]: certbot: error: unrecognized arguments: -post-hook systemctl reload nginx.service

ん? なんか失敗しているね。
「certbot: error: unrecognized arguments: -post-hook systemctl reload nginx.service」とのことで、要は引数-post-hookが違うよって言っている。

待てよ、systemctl reload nginx.serviceて過去にnginx再起動するために追加した何かじゃない……?

ここじゃん!!!!!となり、原因究明。
"-post-hook" systemctl reload nginx.serviceみたいに検索したらすぐに--post-hookの間違いであることがわかったので、よくわからずにコピペで済ますのやめよう……となるのだった。

とか言いつつ、--post-hookについて碌に調べていなかったので、この記事を書きながら軽く調べたのだけれども、--deploy-hookのほうが望ましいのかもしれない。

ということでひとまず、--deploy-hookに修正し、次回更新を確認しようと思う。

ファイルの修正と動作確認

※この章は正直、私の試行錯誤している結果を残しているだけなので、得られるものは何もないと思うよ!

修正内容は結論で最初のほうに記載した通り、certbot.serviceファイルの-post-hook--deploy-hookに修正しただけ。
ただ「この修正内容で問題ないのか……? 他に問題はないのか……?」あたりが気になったので、動作確認をしたくなった。

とりあえずどうにかcertbot.timerを手動実行しよう!(?)と迷宮入りしつつ、必死こいて調べる。
このあたりでようやく、certbot.timerはcertbot.serviceのタイマー設定ファイルなんだな(紐づいているんだな)みたいなのがようやくわかる。
そして、systemd-runというコマンドの存在を知り、「これを使えばなんか行けそうな気がするぞ!」と、いろいろ試すもなんか上手くいかない。
いや、もしかしたらやり方が悪いだけだったり、実は上手くいってたりしたのかもしれない。
この時点で$ certbot certificatesを試していればよかったのだが、あほなのでjounarctlとか、list-timersをひたすら眺めて、う~~~ん?と頭を抱えていた。

しかし、ふとした拍子に、「certbot.serviceを実行する(?)と良いのでは?」と別の発想(?)が生まれる。
でもファイル名叩くのとかもなんか違うよな……と思い、「そもそもcertbot.serviceファイルってどういうこと記載されているんだよ」ということをようやく調べ始める。
そしてたどり着いた、いや、timer調べている時点で多分既にたどり着いていたが、目に入っていなかったありがた情報。

よく見たらserviceファイルの記載についても説明があり、

ExecStart 実行したいコマンド。オプションも指定できる。

と記載されている。

「……実行したいコマンド!? つまりserviceファイルのExecStartに記載していたのがコマンドだから、それを直接叩くだけでいいのでは!?」となる。
あんだけ「コマンドのオプション間違ってたぜ!」と言っていたのに、このあほ、気づくのが遅いのである。

かくして、$ /usr/bin/certbot -q renew --post-hook "systemctl reload nginx.service"と実行してみた。
何も出ずに終わった。
正常終了した、のか……?
jounarctlしてログを見ても何も出ない。
今思えばそれもそうか、という話だが、確かこいつはsystemdで管理しているサービスのログを見るコマンドとかどこかで見ていた気がする。
じゃあletsencrypt.logのほうか!? とログファイルを覗くとなんかいっぱい出てる。
なんならsystemd-runしてたあたりのも出てそうで、それはもうカオス。

結局追うのしんどくなって、$ certbot certificatesすればいいやんとなる。
すると下記が出力され、ひとまず期限が更新されていることがわかった。

$ certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: XXXXX.com
    Serial Number: XXXXXXXXXXXXXXXXXXXXXXXXX
    Key Type: RSA
    Domains: *.XXXXX.com
    Expiry Date: 2025-01-28 07:14:52+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/XXXXX.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/XXXXX.com/privkey.pem
  Certificate Name: XXXXX.XXXXX.com
    Serial Number: XXXXXXXXXXXXXXXXXXXXXXXXX
    Key Type: RSA
    Domains: XXXXX.XXXXX.com
    Expiry Date: 2025-01-28 07:15:02+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/XXXXX.XXXXX.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/XXXXX.XXXXX.com/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

どのタイミングで更新されたんだろう……時間的にはExecStartのコマンドを叩いた時っぽい気がするけど……。
systemd-runしてたときにはもう更新されていた可能性もあるのか……?
……………………とりあえず来年の更新時にまた確認しよう、となるのだった……。

と思ったのだが、この記事を書きながら改めてlogファイルの中身をじっくり見ていると、どうやらコマンドが正常に動いていそうなログを見つけた。
とは言え、知識不足というか翻訳不足というかやる気不足で、きちんとした確証は得られなかったのだが、少しの安心感を得ることはできた。
まあ結局来年を待って確認するしかないんだけどね!
→ 更新できていたね!!

締め

そんなこんなで、結局まだ上手く出来たのかはよく分からないのだけども、いくつか知識が増え、少し前進できたような気がする。
いや、ログを見ろっていうのは当たり前のことなのだが……恐らく前回までは該当のログにたどり着く方法がわからず終わっていたと思うので……。
今後も鯖が動いている以上、何かしらの出来事は起きるだろうが、都度対応できるよう頑張り、たい……頑張りたいのか……? 頑張りたくはない……。努める……。

次回同じようなことが起きたときに、いつぞやかのように泣きを見ないよう、ひとまず備忘録はしっかり残していこうと思う。

余談

ちなみにkmyblueを使用して半年ちょっと経っているようだけど、実家のような安心感で、やはり鯖を建ててよかったと思っている。
ただ最近思うのは、おひとり様サーバーなので当然のことながら、待っているだけではなかなか新しい交流は得られない、ということ。
いや、私は引きこもり体質なので全然それでいいんだけども。
もし、kmyblue関係なくおひとり様サーバーを検討していて、そこで交流を広げたいのであれば、自ら外に向かっていく必要があるということを念頭に置いておいたほうがいいかもなと思った。
まあそのあたりは他者の鯖ぢからをお借りするのも一つの手かも知れない。