Posted at

Let's Encrypt で証明書を小刻みに自動更新

More than 3 years have passed since last update.


  • お手軽 SSL の Let's Encrypt、便利だけど証明書の有効期限が 3ヶ月で切れるのを何とかしたい

  • 証明書の更新コマンドが用意されてるので、自動更新が可能

  • monthly の cron で月1回更新してもいいけど、2,3回連続で失敗したら終わる

  • 公式ドキュメントには下記のようにある。(公式もネットワークトラブルやサーバダウンによる失敗を懸念している)


We recommend running renewal scripts at least daily, at a random hour and minute. This gives the script many days to retry renewal in case of transient network failures or server outages.

How It Works - Let's Encrypt


というわけで、なるべく公式の意に沿うようにやってみる


1日1回、ランダムなタイミングで証明書を更新(そして怒られる)

さすがに毎日はやり過ぎな気はしたけど

0 2 * * * sleep $[($RANDOM % 175)+5]m; /path/to/letsencrypt-renew.sh  >/dev/null 2>&1

※ ログは捨ててない


/path/to/letsencrypt-renew.sh

#!/bin/bash

SCRIPT=/usr/local/src/letsencrypt/letsencrypt-auto
WEBROOT=/path/to/webroot
DOMAIN=example.com
LOG=/var/log/letsencrypt/renew.log

date '+%Y-%m-%d %H:%M:%S >>>' >> $LOG
if ! $SCRIPT certonly --webroot --webroot-path $WEBROOT -d $DOMAIN --renew-by-default >> $LOG 2>&1 ; then
echo ' Automated renewal failed' >> $LOG
exit 1
fi
service nginx reload



  • ランダムと言っても日中は嫌なので、02:05 〜 05:00 の間のどこかでスクリプトが実行される

何回かテストして OK ぽかったので1日待つ。


怒られた

1日待っても証明書が更新されてなかったのでログを見たら


so a SAN multi-domain cert having domain1.com, www.domain1.com, domain2.com, www.domain2.comis counted as 1 certificate ? but you can only renew this SAN multi-domain cert 5 times per 7 days ?


7日に5回までのリミットがかかってるらしい。


5回に1回の確率で証明書を更新するスクリプトを毎日実行

スクリプトの実行自体にもリミットに引っかからない程度のランダム性をもたせてみた。

こう修正して様子見中。

0 2 * * * sh /path/to/letsencrypt-renew.sh  >/dev/null 2>&1

※ ログは捨ててない


/path/to/letsencrypt-renew.sh

#!/bin/bash

SCRIPT=/usr/local/src/letsencrypt/letsencrypt-auto
WEBROOT=/path/to/webroot
DOMAIN=example.com
LOG=/var/log/letsencrypt/renew.log

date '+%Y-%m-%d %H:%M:%S >>>' >> $LOG

# ececute 1/5
if [ $(($RANDOM%5)) -ne 1 ]; then
echo ' do nothing ' >> $LOG
exit;
fi

echo ' sleeping... ' >> $LOG

# sleep 5 - 180 min
sleep $[($RANDOM % 175)+5]m

date '+%Y-%m-%d %H:%M:%S woke up!!>>>' >> $LOG
if ! $SCRIPT certonly --webroot --webroot-path $WEBROOT -d $DOMAIN --renew-by-default >> $LOG 2>&1 ; then
echo ' Automated renewal failed' >> $LOG
exit 1
fi
service nginx reload


# 成功/失敗の結果を Slack とかに通知したらいいと思う