SSL證書的申請、自動續期與常見問題


背景

網絡上已經有很多關於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個方面:

  1. 有證書管理中心時(比如vault),nginx鏡像在啟動的時候,從vault獲取證書。如果獲取不到,但是證書又是必要的,就生成證書,同步到vault,以便鏡像重啟時可以獲取。這個方案的技術細節可參考該文:https://developer.epages.com/blog/tech-stories/managing-lets-encrypt-certificates-in-vault/
  2. 沒有證書管理中心,直接動態生成,具體看下這個鏡像,它就是這么做的: https://github.com/SteveLTN/https-portal

這些處理完全可以做成一個新的nginx鏡像以便重復使用。具體的鏡像如何處理將另開文章討論。

安裝certbot阿里雲DNS插件出錯?

pip install certbot-dns-aliyun

執行上面命令時報出下面的錯誤:

'extras_require' must be a dictionary whose values are strings or lists of strings containing valid project/version requirement specifiers. #1268

解決方法:

pip install --user --upgrade setuptools

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM