重い腰をあげてLet's Encryptの自動更新をcron化したけど結構苦労したわ
— しまぶ (@shimabox) September 28, 2018
というわけで、Let's Encrypt
の自動更新をcron化したわけなのですが、つぶやいているとおり地味に苦労した部分があったのでその際のメモです。
なお、自分の環境は
- CentOS 6.9
- Let’s Encryptを導入済み
standalone
プラグイン利用
となっております。
はじめに
まず今までの更新は以下の手順で行っていました。
$ sudo service httpd stop $ /path/to/certbot/certbot-auto certonly --standalone -d shimabox.net -d blog.shimabox.net $ sudo service httpd start
※ certbot
のパスは自身のもので読み替えてください
※ --webroot
ではなく、--standalone
を使っているので一旦apacheを止める必要があります
※ 最近サブドメのワイルドカードもいけるようになったっぽい
これを Let's Encrypt Expiry Bot
から、もうそろそろ有効期限が切れますよ〜 というメールが届くたびに手動で行うのです。
最初は別になんとも思わなかったけど、さすがにもうめんどうくさいのと、今の時代決まりきっていることを手動で行うのはナンセンスすぎる。
という思考の末、自動化(cron)を決意した次第であります。
最初のつまずき
ひさびさに情報を漁ってみると、 更新には renew コマンドを使うのが正解のようです。
念のため、—dry-run と組み合わせて直接試してみます。
$ sudo /path/to/certbot/certbot-auto renew --dry-run
こんなエラーでました
Problem binding to port 80: Could not bind to IPv4 or IPv6.. Skipping. All renewal attempts failed. The following certs could not be renewed
これは、standalone プラグイン
が TCP Port 80 や TCP Port 443 をListenしているため。だそうです。
つまり、一旦apche(80)を止めないとだめ。
というか手動でやっていたとき httpd stop
, httpd start
をやってたやないの。
落ち着け。そしてありがとう、dry-run。
pre-hook, post-hook
手動作業どおりに更新処理の前と後で httpd
をゴニョるにはどうすればいいのか調べると、
を使えばいいということがわかります。
pre-hook
で httpd stop
、post-hook
で httpd start
をやればよさそうです。
$ sudo /path/to/certbot/certbot-auto renew --dry-run --pre-hook "sudo service httpd stop" --post-hook "sudo service httpd start"
成功
Congratulations, all renewals succeeded. The following certs have been renewed:
こんなメッセージが出れば成功です。
※ もちろんdry-run
なので実際には更新されていません
さぁ、あとはこのコマンドをcronでの定期実行を設定すれば自動化が完成です。
cron
まずcronの設定を確認します。
起動確認
起動しているか確認します。
$ service crond status
起動
起動していなければ起動します。
$ sudo service crond start
設定
root
になって作業します。
今回は、/etc/crontab
に書くのではなく、/etc/cron.d
にletsencrypt用として書くことにします。
# vi /etc/cron.d/letsencrypt
この時点では木曜日だったので、とりあえず 金曜日(5) 午前4:00 に実行されるように指定しておきます。
※ 実際の運用では 土曜日(6) 午前4:00 とします
0 4 * * 5 root /your/path/certbot/certbot-auto renew --pre-hook "service httpd stop" --post-hook "service httpd start"
wktkしながら次の日を待ちます。
次のつまずき
次の日、うんともすんともいっていない。。
ログ(/var/log/letsencrypt/letsencrypt.log
)も確認したけど、起動すらされていない模様。これは悲しい。
こんなときはデバッグだ
こんな感じで、ログを仕込む && cronの実行時間をいじって確認してみます。
* * * * * root /your/path/certbot/certbot-auto renew --pre-hook "service httpd stop" --post-hook "service httpd start" >>/tmp/analog.log 2>>/tmp/analog-err.log
参考: Let’s Encryptをcrontabで自動化した時に実行されない時の対処法
こんなんでました
# cat /tmp/analog-err.log Unable to find pre-hook command service in the PATH. (PATH is /usr/bin:/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin)
わお、PATHが通っていない。。?だと??
実際の環境変数だとservice
は以下にPATHが通っています。
# which service /sbin/service
え、なんで?どういうこと?むーわからん。
こんなときはデバッグだ!! というわけで、
cronジョブを作るのにいつものやり方でいいんですか?
を参考にcron実行時の環境変数を出力してみます。
* * * * * root env >/tmp/cron_env
# cat /tmp/cron_env SHELL=/bin/sh USER=root PATH=/usr/bin:/bin PWD=/root LANG=ja_JP.UTF-8 SHLVL=1 HOME=/root LOGNAME=root _=/usr/bin/env
へぇ。/usr/bin
, /bin
にしか通っていないんやねぇ。。これは悲しい。
(この記事にもありますが)ちょっと調べてみると、
なんと、cronの各ジョブ実行時には,環境変数は最低限しかセットされていないとのことです。
なんと、cronの各ジョブ実行時には,環境変数は最低限しかセットされていないとのことです。
大事なことなので、2回書きました。
PATHを通す
では、上の 記事 を参考に/sbin
を通してみます。
* * * * * root PATH="/sbin:$PATH" env >/tmp/cron_env
確認。
# cat /tmp/cron_env PATH=/sbin:/usr/bin:/bin SHELL=/bin/sh USER=root PWD=/root LANG=ja_JP.UTF-8 SHLVL=1 HOME=/root LOGNAME=root _=/usr/bin/env
通った。
再度確認
再び実行時間をいじって実行してみます。
* * * * * root PATH="/sbin:$PATH" /your/path/certbot/certbot-auto renew --pre-hook "service httpd stop" --post-hook "service httpd start"
結果
ログ(/var/log/letsencrypt/letsencrypt.log
) にも
certbot.renewal:no renewal failures
こんな感じでエラーも出ていないようだし、実際のサイトも更新出来ている。
、、おし。できた。
最終設定
最後にきちんと設定(毎週土曜の午前4:00に実行される様に)して、完了です。
くぅ、無知は辛い。
/etc/cron.d/letsencrypt
0 4 * * 6 root PATH="/sbin:$PATH" /your/path/certbot/certbot-auto renew --pre-hook "service httpd stop" --post-hook "service httpd start"
次の土曜と3ヶ月後にまた確認しよう。
追記
(確認するのを忘れていましたが、)きちんと更新されているようです。
おわりに
cronにはユーザの環境変数が引き継がれない ということを認識していなかったという無知が引き起こした無駄工数を体験出来ました。
しかし、こういう経験を経て人はまた強くなるのです。
参考にさせていただきました
- Let’s Encryptをcrontabで自動化した時に実行されない時の対処法
- cronジョブを作るのにいつものやり方でいいんですか?
- Let’sEncryptの取得&自動更新設定してみた(CentOS7.1&Apache2.4.6)
- Let’s Encryptを使ってSSL証明書を自動更新する(AWS/Amazon Linux/Apache)
- クーロン(cron)をさわってみるお
- 第25回 cron周りのベストプラクティス(1):Perl Hackers Hub|gihyo.jp … 技術評論社
- /etc/crontabと/etc/cron.d設定ファイルの書き方 | server-memo.net
Centos6.10でどうしてもcrontaで自動化したいと思い、調べてたらこちらのページに辿り着きました。
とても、参考になりました。
トムさん
こちらこそお役に立てて嬉しいです。ありがとうございます。
グーグルから来ました。
私も数日前にcronにcertbot実行を設定してご機嫌でHP更新に励んでいたのですが、今日cronからメールを受信。
私は毎週日曜日に実行する設定にしていたのでした。
メールの内容は「証明書の更新はまだ必要ない」というもの。
このメールが毎週送られてくるのは地味にしんどくないですか。
更新に失敗したとかの重要な通知は必要ですが、このような事務連絡レベルの通知は来ないようにしたいです。
ググってもあまり出てこないので皆さん気にしないのですかね。