1. 程式人生 > >手把手教你搭建基於 Let’s Encrypt 的免費 HTTPS 證書

手把手教你搭建基於 Let’s Encrypt 的免費 HTTPS 證書

作者:劉剛,叩丁狼高階講師。原創文章,轉載請註明出處。

Let’s Encrypt 是國外一個公共的免費 SSL 專案,該專案是為了普及 HTTPS 而發起的,目前已經被 Mozilla、Google、Microsoft 和 Apple 等主流瀏覽器支援,對 HTTPS 技術的普及有著巨大貢獻。隨著 HTTPS 的普及,Let’s Encrypt 已經成為全球最受歡迎的免費 SSL 證書籤發機構。

注意事項

  • Let’s Encrypt 的基礎證書只提供了資料加密,不驗證身份,從而也無法證明網站的所有者,雖然已經滿足絕大部分應用場景,但若涉及核心功能時還是需要進行身份驗證。
  • Let’s Encrypt 簽發的證書一次的有效期為 3 個月,需要定期更新證書(官方推薦兩個月左右更新一次,本文有提供自動更新方案)。

安裝 EPEL 倉庫

Let’s Encrypt 的簽發證書工具在 EPEL 倉庫中才能找到,所以如果沒有安裝 EPEL 倉庫的話要先安裝一下。

# 查詢是否已安裝 epel 倉庫
rpm -qa epel-release
# 若沒有安裝再安裝 epel 倉庫
sudo yum install -y epel-release

安裝簽發證書工具

用 Certbot 工具申請 Let’s Encrypt 證書,要先安裝該工具:

sudo yum install certbot-nginx

如果報以下錯誤:

ImportError:No module named 'requests.packages.urllib3'

執行以下命令解決:

# 如果沒有 pip 可使用 `sudo yum install python-pip` 安裝
pip install --upgrade --force-reinstall 'requests==3.6.0' urllib3

網站執行在申請 SSL 證書的伺服器上

這邊將申請證書分為兩種情況,正常情況下我們使用第一種就好了,也就是網站執行在申請 SSL 證書的伺服器上。另外就是比如在 A 機器上申請證書,但網站執行在 B 機器上,當然如果你是用 Docker 跑的 Nginx 也得用第二種方式。

第一種方式有以下幾個條件:

i. 你要申請 SSL 證書的域名已經指向到申請證書伺服器的 ip
ii. 你的 Web 伺服器需要使用 Nginx(在本例子中,可以在官網檢視其它伺服器的方式)
iii. Nginx 配置完成,並且已經綁定了你要申請 SSL 證書的域名

具備以上條件,就可以執行以下操作啦:

# 申請 SSL 證書,certonly 表示只生成證書,不做額外操作
sudo certbot --nginx certonly

certbot 會自動查詢當前 Nginx 上的虛擬主機,並提示:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org

Which names would you like to activate HTTPS for?
-------------------------------------------------------------------------------
1: xxx.wolfcode.cn
-------------------------------------------------------------------------------
Select the appropriate numbers separated by commas and/or     spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1

如果出現以下錯誤:

# Saving debug log to /var/log/letsencrypt/letsencrypt.log
# The nginx plugin is not working; there may be problems with your existing configuration.
# The error was: NoInstallationError()

可能是因為找不到 nginx 命令,解決方案:

# 以下命令是分別將 nginx 安裝目錄的 nginx 命令與配置檔案軟連線到指定檔案
# 你可以根據自己的具體情況修改目錄
ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
ln -s /usr/local/nginx/conf /etc/nginx

還有可能提示無法連線到你的伺服器,主要要開放防火牆的 443 埠
看到前面正確提示,出現我的 Nginx 上繫結的一個域名,如果你的 Nginx 有繫結多個,那麼列表中也會以多個顯示,然後輸入你需要申請 SSL 證書對應域名的序號即可,驗證成功後 Let’s Encrypt 就會立即給你簽發 SSL 證書,成功後提示:

# Obtaining a new certificate
# Performing the following challenges:
# tls-sni-01 challenge for g.wangchujiang.com
# Waiting for verification...
# Cleaning up challenges
# 
# IMPORTANT NOTES:
#  - Congratulations! Your certificate and chain have been saved at:
#    /etc/letsencrypt/live/xxx.wolfcode.cn/fullchain.pem
#    Your key file has been saved at:
#    /etc/letsencrypt/live/xxx.wolfcode.cn/privkey.pem
#    Your cert will expire on 2018-03-29. To obtain a new or tweaked
#    version of this certificate in the future, simply run certbot
#    again. To non-interactively renew *all* of your certificates, run
#    "certbot renew"
#  - If you like Certbot, please consider supporting our work by:
# 
#    Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
#    Donating to EFF:                    https://eff.org/donate-le

以上資訊則表示證書生成成功了。其他資訊主要是告訴你證書存放的位置、過期時間以及更新證書命令:

# 證書位置
/etc/letsencrypt/live/xxx.wolfcode.cn/fullchain.pem
/etc/letsencrypt/live/xxx.wolfcode.cn/privkey.pem
# 過期時間:Your cert will expire on 2018-06-19.
# 你的證書將在 2018-06-19 過期
# 可以使用如下命令更新證書有效期
certbot renew --dry-run

配置 Nginx,讓所有 HTTP 請求轉發到 HTTPS:

# 將 http 請求轉發到 https
server {
    listen       80;
    server_name  xxx.wolfcode.cn;
    rewrite     ^(.*)$ https://$host$1 permanent;
    # 禁止在 heaader 中出現伺服器版本,防止黑客利用版本漏洞攻擊
    server_tokens off;
}

# https 的配置
server {
    listen     443 ssl;
    server_name     xxx.wolfcode.cn;

    ssl_certificate    /etc/letsencrypt/live/xxx.wolfcode.cn/fullchain.pem;
    ssl_certificate_key    /etc/letsencrypt/live/xxx.wolfcode.cn/privkey.pem;
    # 禁止在 heaader 中出現伺服器版本,防止黑客利用版本漏洞攻擊
    server_tokens    off;
    # 設定ssl/tls會話快取的型別和大小。如果設定了這個引數一般是shared,buildin可能會引數記憶體碎片,預設是none,和off差不多,停用快取。如shared:SSL:10m表示我所有的nginx工作程序共享ssl會話快取,官網介紹說1M可以存放約4000個sessions。
    ssl_session_cache    shared:SSL:1m;


    # 客戶端可以重用會話快取中ssl引數的過期時間,內網系統預設5分鐘太短了,可以設成30m即30分鐘甚至4h。
    ssl_session_timeout  5m;

    # 選擇加密套件,不同的瀏覽器所支援的套件(和順序)可能會不同。
    # 這裡指定的是OpenSSL庫能夠識別的寫法,你可以通過 openssl -v cipher 'RC4:HIGH:!aNULL:!MD5'(後面是你所指定的套件加密演算法) 來看所支援演算法。
    ssl_ciphers  HIGH:!aNULL:!MD5;

    # 設定協商加密演算法時,優先使用我們服務端的加密套件,而不是客戶端瀏覽器的加密套件。
    ssl_prefer_server_ciphers  on;

    location / {
        root   /www/html/website;
        index  dist/index.html;
    }

    error_page     404    /404.html;
    location = /404.html {
    root    html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

到此就配置完成啦,使用 HTTPS 訪問看看吧。

網站執行在申請 SSL 證書以外的伺服器上

為其他主機上的網站或 Docker 中的網站申請 SSL 證書,只需要多一步驗證即可:

# 申請證書
# certonly 只生成證書,不做額外操作
# --manual 互動式操作,也就是追加驗證條件
sudo certbot certonly --manual

提示讓你輸入想要申請證書的域名

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel): xxx.wolfcode.cn

接著會提示需要記錄你申請 SSL 證書域名對應伺服器的 IP,問你是否同意:

Obtaining a new certificate
Performing the following challenges:
http-01 challenge for ninghao.net

-------------------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
-------------------------------------------------------------------------------
(Y)es/(N)o: Y

然後會給一個字串,讓你將字元內容儲存在一個檔案內,並可以通過它所指定的 URL 進行訪問,cretbot 會對該 URL 進行校驗

-------------------------------------------------------------------------------
Create a file containing just this data:

HNIVXWGNL99iXcy5zI9OwSZmugf0xnv786nw5HchlJ4.n3Pm5l0vxnRwAslvOBBkXT1rGGJ7AwbTnaSCsSiQJFc

And make it available on your web server at this URL:

http://wolfcode.cn/.well-known/acme-challenge/HNIVXWGNL99iXcy5zI9OwSZmugf0xnv786nw5HchlJ4

-------------------------------------------------------------------------------
Press Enter to Continue

比如我這個,則可以在 website 根目錄建立:

# 建立驗證資料夾
mkdir -p /yourwebsite/.well-known/acme-challenge/
# 進入該資料夾
cd /yourwebsite/.well-known/acme-challenge/
# 建立檔案(以下兩部內容請修改為你自己的資料)
touch HNIVXWGNL99iXcy5zI9OwSZmugf0xnv786nw5HchlJ4
# 將提示資訊寫入檔案
echo "HNIVXWGNL99iXcy5zI9OwSZmugf0xnv786nw5HchlJ4.n3Pm5l0vxnRwAslvOBBkXT1rGGJ7AwbTnaSCsSiQJFc" > HNIVXWGNL99iXcy5zI9OwSZmugf0xnv786nw5HchlJ4

驗證通過之後便會簽發證書:

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/wolfcode.cn/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/wolfcode.cn/privkey.pem
   Your cert will expire on 2018-03-29. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

到此證書申請便完成了,Nginx 配置可以參考上面的配置

新增定時任務完成自動更新

現在證書申請、配置都已經完成了,並且也可以正常訪問,但還有個小問題就是 Let’s Encrypt 簽發的證書只有 90 天的有效期,到期後需要再更新,此時便可以使用到 linux 上的 crontab 工具來定時幫我們完成更新操作
certbot 為我們提供了很方便的更新方式,你只需要執行如下命令:

# 更新所有證書
sudo certbot renew --dry-run
使用以上命令便可以將所有證書更新,那麼此時我們可以新增一個定時任務來完成這一操作:
# 進入定時任務存放目錄
cd /etc/cron.d
# 將指令碼寫入檔案,該指令碼是每 2 個月的 20 號凌晨 2:15 執行一次
echo "15 2 20 */2 * certbot renew --dry-run" > certbot-auto-renew-cron
# 將指令碼加入到 crontab
crontab certbot-auto-renew-cron

至此,SSL 證書就算徹底完成啦。