背景
網絡上已經有很多關於Let's encrypt
免費申請證書的文章,但是基本只談最基礎用法,立刻用起來是沒問題了。但是在實際使用中,碰到了一些問題則比較頭疼。整理以后,大概出在以下幾個方面:
- 單域名和泛域名的申請方式上有區別;
- 單域名和泛域名的證書如何自動續期;
- 如果提前驗證自動續期是正常的;
- 選擇文件驗證還是DNS驗證;
- 如何與docker有效配合;
本文的價值在於闡述了解決這些問題的具體思路。
安裝工具
申請Let's encrypt
證書,既可以使用certbot
官方工具,也可以使用acme.sh
第三方工具,各有各的好處,主要看偏好,本文使用certbot
演示。
安裝指南 :直接進《certbot官方安裝指南》,選擇nginx和自己的操作系統,就會生成對應的安裝指南。
文件驗證與DNS驗證
在給域名申請證書時,Let's encrypt
需要先驗證你有對域名的控制權。這個驗證方式有2種:文件驗證和DNS驗證。
文件驗證的原理是在你的網站下面放一個驗證文件(/.well-known/acme-challenge/
目錄下),certbot
通過域名直接訪問到這個驗證文件,能訪問到說明是你的網站,也就可以申請證書。
DNS驗證的原理是你需要創建一條TXT
的記錄,設置指定值,certbot
檢查到這條記錄就完成驗證。
兩種方式各有其適用場景,對於自己可以控制的域名,直接通過DNS
驗證是最便捷的,不需要任何nginx
的輔助就可以完成申請和續期。但是很多時候,我們是給客戶提供服務,並沒有域名的控制權,就只能使用文件驗證的方式。假如使用了DNS
的驗證方式,客戶首次申請是要手動改DNS
記錄,等到過期后,也不能自動續期,需要再次手動調整DNS
記錄。
為保證域名正常續期,本文的單域名證書的申請上,使用的是文件驗證的方式。
單域名證書的申請與自動續期
申請證書
對於單域名,我們統一使用文件驗證的方式,因此要先寫好nginx
的配置文件:
server {
listen 80;
server_name www.papamk.com;
root /var/www/html;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/html;
access_log off;
}
return 301 https://www.papamk.com$request_uri;
}
訪問curl http://www.papamk.com
將會返回如下結果:
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
接着開始申請證書:
certbot certonly --webroot -w /var/www/html -d www.papamk.com
編輯nginx
配置文件,給HTTPS
增加證書的相關配置,重點是以下2名:
ssl_certificate /etc/letsencrypt/live/www.papamk.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.papamk.com/privkey.pem;
完整的nginx
配置如下:
server {
listen 443 ssl;
server_name www.papamk.com;
root /var/www/html;
index index.php index.html index.htm;
access_log /dev/stdout;
error_log /dev/stderr;
ssl_certificate /etc/letsencrypt/live/portfolia.papamk.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/portfolia.papamk.com/privkey.pem;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
internal;
try_files $uri /index.php =404;
fastcgi_intercept_errors on;
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
以上配置使用
php
作為示例。
更新證書與自動續期
certbot renew --deploy-hook 'nginx -s reload'
當證書在30天內過期時,就會自動更新,更新成功會重新加載nginx
。
放在crontab中,每天凌晨1點更新。
0 1 * * * certbot renew --deploy-hook 'nginx -s reload'
泛域名證書的申請與自動續期
泛域名證書只支持DNS驗證的方式,所以如果不能直接修改DNS記錄,泛域名證書過期后就會需要手動更新。要解決這個問題,需要使用對應的DNS插件,國外的主流DNS插件都有內置支持,如果是國內。我基本都使用阿里雲,官方certbot
沒有對應的DNS插件,但是第三方有,傳送門:
https://github.com/tengattack/certbot-dns-aliyun
安裝certbot阿里雲dns插件
pip install certbot-dns-aliyun
創建aliyun.ini
,寫入授權信息(授權賬號需要有AliyunDNSFullAccess
)
certbot_dns_aliyun:dns_aliyun_access_key = 12345678
certbot_dns_aliyun:dns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef
修改下權限:
chmod 600 aliyun.ini
接下來就可以開始使用了。
申請證書
certbot certonly -a certbot-dns-aliyun:dns-aliyun --certbot-dns-aliyun:dns-aliyun-credentials aliyun.ini -d '*.yourdomain.com' --server https://acme-v02.api.letsencrypt.org/directory
更新證書與自動續期
certbot renew -a certbot-dns-aliyun:dns-aliyun --certbot-dns-aliyun:dns-aliyun-credentials aliyun.ini --server https://acme-v02.api.letsencrypt.org/directory --deploy-hook 'nginx -s reload'
放到crontab
每天自動檢查:
0 1 * * * certbot renew -a certbot-dns-aliyun:dns-aliyun --certbot-dns-aliyun:dns-aliyun-credentials aliyun.ini --server https://acme-v02.api.letsencrypt.org/directory --deploy-hook 'nginx -s reload'
這里的每天檢查與單域名的每日檢查2選1即可。
常見問題
證書存放位置?
證書一般存放在如下路徑:/etc/letsencrypt/live/
。
每個域名一個文件夾,可以看到www.yourdomain.com
的目錄。
如何提前驗證自動續期后可以重新加載nginx?
先進瀏覽器,看下當前證書的過期時間,然后執行強制更新:
certbot renew --force-renew --deploy-hook 'nginx -s reload'
再次進瀏覽器,查看當前證書的過期時間,如果日期有變,說明nginx
重新加載了。
如何保證過期前證書就得到更新?
certbot renew
會對30天
以內的證書更新,只要保證cron
有執行每天定時更新一次就沒問題。第一次使用時,證書在30以內要注意下這個問題,確保它們得到了更新。
域名解析到內網,申請證書不成功?
根據文件驗證的原理,certbot
無法訪問到你的內網,也就驗證不通過。使用DNS
驗證可以申請成功。
Docker鏡像的nginx如何獲取證書與更新?
在許多文章中,都是通過volume
將主機的/etc/letsencrypt
掛載到容器中,但是在生產環境時,由於應用變成了有狀態應用,這種方式有很大的局限性。從A機器遷移到B機器時,將會立刻報錯,必須手動解決完證書問題。推薦的做法是將證書做成動態獲取的,具體來說要考慮以下2個方面:
- 有證書管理中心時(比如
vault
),nginx
鏡像在啟動的時候,從vault
獲取證書。如果獲取不到,但是證書又是必要的,就生成證書,同步到vault
,以便鏡像重啟時可以獲取。這個方案的技術細節可參考該文:https://developer.epages.com/blog/tech-stories/managing-lets-encrypt-certificates-in-vault/ - 沒有證書管理中心,直接動態生成,具體看下這個鏡像,它就是這么做的: https://github.com/SteveLTN/https-portal
這些處理完全可以做成一個新的nginx
鏡像以便重復使用。具體的鏡像如何處理將另開文章討論。
安裝certbot阿里雲DNS插件出錯?
pip install certbot-dns-aliyun
執行上面命令時報出下面的錯誤:
解決方法:
pip install --user --upgrade setuptools