Let’s Encrypt證書自動更新
Let’s Encrypt免費SSL證書用起來非常方便,但每次申請只有三個月有效期,在每次到期之前都需要重新申請,不過重新申請並不麻煩,只需要一行命令就完事:certbot renew
。
即便是一條命令就OK,也不想每隔三個月就需要登錄到機器上執行更新命令,所以我在第一次申請之後就配置了crontab每隔兩個月重新申請一次。
願景是美好的,但過了一段時間後,我網站證書竟然過期了,也就是說crontab沒有生效或者任務失敗了,此文就是來找到這個問題所在以及修復它。
history
v1
最開始我配置了一條這樣的crontab:
0 0 1 */2 * certbot renew --force-renewal
然後發現不生效,鑑於之前的經驗知道crontab執行命令的路徑應該是$HOME
,而且不會加載環境變量,所以在這裏改了一下。
v2
通過which certbot
查找到命令的完整路徑,然後配置到crontab中:
0 0 1 */2 * /usr/bin/certbot renew --force-renewal
但過了一段時間後發現網站的證書沒有更新,自己依舊沒當回事,覺得可能是month: */2這個寫法不對。
v3
雖然之前在crontab文檔裏面是見過*/2
這種寫法的,但這次沒去深究,遂改成1,3,5…逗號的寫法:
0 0 1 1,3,5,7,9,11 * /usr/bin/certbot renew --force-renewal
結果依舊悲催。
v4
悲催後,我又改了下:
0 0 1 1,3,5,7,9,11 * /usr/bin/certbot renew --quiet --force-renewal 1>/dev/null 2>/dev/null
寫這篇文章就是發生在第四次瞎B試失敗後,受不了了…
now
crontab日誌
爲了驗證,這次就不再是配置兩個月間隔的crontab,就看着時間配置,比如現在是13:57,那麼crontab裏面就配置成:
0 14 * * * /usr/bin/certbot renew --quiet --force-renewal 1>/dev/null 2>/dev/null
到了14:00,去找crontab的日誌(/var/log/cron),發現是命令是執行的,而且沒有什麼有效信息,日誌內容如下:
Jul 4 14:00:01 ams CROND[21881]: (root) CMD (/usr/bin/certbot renew --quiet --force-renewal 1>/dev/null 2>/dev/null)
Jul 4 14:00:01 ams CROND[21882]: (root) CMD (echo "tmp" > /root/tmp)
Jul 4 14:00:01 ams CROND[21883]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Jul 4 14:01:01 ams CROND[22000]: (root) CMD (run-parts /etc/cron.hourly)
Jul 4 14:01:01 ams run-parts(/etc/cron.hourly)[22000]: starting 0anacron
Jul 4 14:01:01 ams run-parts(/etc/cron.hourly)[22009]: finished 0anacron
其中echo "tmp" > /root/tmp
是自己不清楚如何查看crontab日誌的情況下用來驗證crontab是否執行。
最終通過日誌以及/root/tmp
確認命令有被執行,但證書就是沒有更新,由於通過手動執行命令可以更新證書,這裏判斷命令在crontab裏面就不好使了,具體原因還不清楚。
letsencrypt日誌
crontab日誌中沒什麼發現,進入Google搜索模式幾分鐘後發現letsencrypt有自己的日誌:/var/log/letsencrypt/letsencrypt.log,遂查看:
2018-07-04 14:00:02,500:DEBUG:certbot.main:certbot version: 0.23.0
2018-07-04 14:00:02,500:DEBUG:certbot.main:Arguments: ['--quiet', '--force-renewal']
2018-07-04 14:00:02,500:DEBUG:certbot.main:Discovered plugins: PluginsRegistry(PluginEntryPoint#manual,PluginEntryPoint#nginx,PluginEntryPoint#null,PluginEntryPoint#standalone,PluginEntryPoint#webroot)
2018-07-04 14:00:02,516:DEBUG:certbot.log:Root logging level set at 30
2018-07-04 14:00:02,516:INFO:certbot.log:Saving debug log to /var/log/letsencrypt/letsencrypt.log
2018-07-04 14:00:02,543:DEBUG:certbot.plugins.selection:Requested authenticator <certbot.cli._Default object at 0x36b5550> and installer <certbot.cli._Default object at 0x36b5550>
2018-07-04 14:00:02,546:DEBUG:certbot.renewal:Auto-renewal forced with --force-renewal...
2018-07-04 14:00:02,565:DEBUG:certbot.plugins.selection:Requested authenticator nginx and installer nginx
2018-07-04 14:00:02,570:DEBUG:certbot.plugins.disco:No installation (PluginEntryPoint#nginx):
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/certbot/plugins/disco.py", line 126, in prepare
self._initialized.prepare()
File "/usr/lib/python2.7/site-packages/certbot_nginx/configurator.py", line 135, in prepare
raise errors.NoInstallationError
NoInstallationError
2018-07-04 14:00:02,570:DEBUG:certbot.plugins.selection:No candidate plugin
2018-07-04 14:00:02,570:DEBUG:certbot.plugins.selection:No candidate plugin
2018-07-04 14:00:02,571:DEBUG:certbot.plugins.selection:Selected authenticator None and installer None
2018-07-04 14:00:02,571:INFO:certbot.main:Could not choose appropriate plugin: The nginx plugin is not working; there may be problems with your existing configuration.
The error was: NoInstallationError()
2018-07-04 14:00:02,571:WARNING:certbot.renewal:Attempting to renew cert (www.isenle.com) from /etc/letsencrypt/renewal/www.isenle.com.conf produced an unexpected error: The nginx plugin is not working; there may be problems with your existing configuration.
The error was: NoInstallationError(). Skipping.
2018-07-04 14:00:02,571:DEBUG:certbot.renewal:Traceback was:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/certbot/renewal.py", line 422, in handle_renewal_request
main.renew_cert(lineage_config, plugins, renewal_candidate)
File "/usr/lib/python2.7/site-packages/certbot/main.py", line 1095, in renew_cert
installer, auth = plug_sel.choose_configurator_plugins(config, plugins, "certonly")
File "/usr/lib/python2.7/site-packages/certbot/plugins/selection.py", line 201, in choose_configurator_plugins
diagnose_configurator_problem("authenticator", req_auth, plugins)
File "/usr/lib/python2.7/site-packages/certbot/plugins/selection.py", line 297, in diagnose_configurator_problem
raise errors.PluginSelectionError(msg)
PluginSelectionError: The nginx plugin is not working; there may be problems with your existing configuration.
The error was: NoInstallationError()
這堆異常大概是說沒有安裝nginx插件,結合自己機器上安裝了nginx以及手動執行renew是OK的,所以猜測這裏是因爲crontab執行renew時找不到相關程序導致,而程序存在卻找不到,無非就是PATH有問題,遂進行驗證:
20 14 * * * echo "$PATH" > /root/tmp
到時間後查看/root/tmp
發現內容是:/usr/bin:/bin
,而which nginx
的結果是:/usr/sbin/nginx
,基本可以確定是PATH的問題,所以現在把crontab的環境變量配置一下就OK了,用crontab -e進入編輯,在最前面加上兩行環境設置:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
0 0 1 */2 * certbot renew --quiet --force-renewal
花了半小時,問題最終得到解決,以後就不用管證書的自動續期了。
review
針對這件事情做個review,從自己v1-v4的處理中,總結出自己的一些缺點:
- 馬虎對待,不求甚解
- 處理問題的方式不對,只是瞎B試
- 知識不牢靠,比如crontab的PATH、*/2等
這篇文章不是解決問題後所寫,而是當我決定來解決這個問題的時候開始寫的,最開始以爲是Let’s Encrypt的問題,最後發現與Let’s Encrypt並沒有關係,只是crontab的PATH問題而已。
crontab有兩種使用方式,一種是編輯/etc/crontab
,一種是用crontab -e
,前者默認配置了SHELL與PATH,而我在這裏使用的是crontab -e
,所以弄出這麼個問題。