背景
服務器使用 OneinStack(Linux + Nginx+ MySQL/MongoDB+ PHP) 服務,在安裝 OneinStack 的時候,選擇安裝了 Let’s Encrypt 免費 SSL 證書,而 Let’s Encrypt 免費 SSL 證書現(xiàn)在據(jù)說是 90 天有效,到期需要續(xù)期。安裝 OneinStack 包會自動在 crontab 中添加自動續(xù)期的命令,講道理,系統(tǒng)會自動續(xù)期,但是在 Let's Encrypt 證書還有 30 天到期之前,居然收到了官方郵件,提示說證書會過期并建議盡快續(xù)期。這說明自動續(xù)期的命令沒有執(zhí)行或者是執(zhí)行過程中出錯了。
確認問題
經(jīng)過排查,定時任務命令 crontab 是有效的,那么就說明自動續(xù)期的命令出錯了,那么得手動看看到底出了什么錯。首先找到關(guān)于 certbot 的執(zhí)行續(xù)期的命令,從 crontab 文件內(nèi)容中就可以找到該命令:
crontab -l
可以看到續(xù)期的命令是:
/usr/local/python/bin/certbot renew --force-renew --renew-hook "/etc/init.d/nginx reload"
然后手動執(zhí)行該命令,結(jié)果果然報錯了:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/www.example.com.conf
-------------------------------------------------------------------------------
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for www.example.com
Waiting for verification...
Cleaning up challenges
Attempting to renew cert from /etc/letsencrypt/renewal/www.example.com.conf produced an unexpected error: Failed authorization procedure. www.example.com (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.example.com/.well-known/acme-challenge/FeKzKrTsEN_Z-j7ixVz6q2vnorNN-ZBJTWRDFKK0k38: "<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="I". Skipping.
IMPORTANT NOTES:
The following errors were reported by the server:
Domain: www.example.com
Type: unauthorized
Detail: Invalid response from
http://www.example.com/.well-known/acme-challenge/3DDhheqPSYDx0LVwARFFx1N6J0KRd7Q3fMK8c9600W0:
"
<meta na"
To fix these errors, please make sure that your domain name was
entered correctly and the DNS A record(s) for that domain
contain(s) the right IP address.
原因分析
上 letsencrypt 官網(wǎng)找到一條 QA(https://community.letsencrypt.org/t/cant-certbot-renew-in-nginx/38786),官方人員給出第一個建議是檢查 /etc/letsencrypt/renewal/www.example.com.conf 文件中的 webroot_map 內(nèi)容,是否對應的網(wǎng)站根目錄,如果 conf 文件中的 webroot_map 的地址不是網(wǎng)站的根目錄,就會報錯。
然后查看一下 www.example.com.conf 文件的內(nèi)容:
cat /etc/letsencrypt/renewal/www.example.com.conf
發(fā)現(xiàn) [[webroot_map]] 下面的地址,果然不是根目錄,于是嘗試修改為根目錄后,再次執(zhí)行 renew 續(xù)期的命令,就續(xù)期成功了:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/www.example.com.conf
-------------------------------------------------------------------------------
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for www.example.com
Waiting for verification...
Cleaning up challenges
Running renew-hook command: /etc/init.d/nginx reload
Output from nginx:
Reloading nginx configuration (via systemctl): [ OK ]
-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/www.example.com/fullchain.pem
-------------------------------------------------------------------------------
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/www.example.com/fullchain.pem (success)