使用 Dehydrated 申請 Let’s Encrypt 免費 SSL 憑證

選用 dehydrated 而非官方的 certbot 有以下優點:

  • dehydrated 的需求相當低,只需要有 curl(wget) 與 openssl 就可以執行
  • certbot 需要 Python,在更新時遇到模組相依性問題,無法正常執行

安裝過程

下載最新 release 的 dehydrated(只抓執行檔即可)

curl -LO //raw.githubusercontent.com/lukas2511/dehydrated/master/dehydrated

把程式安裝到 /etc/dehydrated/ 下:

mkdir /etc/dehydrated/
cp ./dehydrated /etc/dehydrated/
chmod a+x /etc/dehydrated/dehydrated

建立 SSL certificate 證驗證過程時所需要的目錄:

mkdir -p /var/www/dehydrated/
(下面這行不確定是否必要)
mkdir -p /usr/share/nginx/html/.well-known/acme-challenge/

生成 DH Parameter

mkdir /etc/dehydrated/ssl/
openssl dhparam -out /etc/dehydrated/ssl/dhparam.pem 2048

 

設定 NGINX,在要認證的 virtual host 裡加上:

location /.well-known/acme-challenge/ {
    alias /var/www/dehydrated/;
}

重新載入 NGINX 設定

systemctl reload nginx

第一次需要先同意 Let’s Encrypt 的條款:

/etc/dehydrated/dehydrated --register --accept-terms

會看到下方的訊息

# !! WARNING !! No main config file found, using default config!
#
+ Generating account key...
+ Registering account key with ACME server...
+ Done!

第一次產生 SSL certificate,紅色的部份請代換成網域名稱:

/etc/dehydrated/dehydrated -c -d odoo.gapl.com.tw

成功的話會有類似的輸出:

#
# !! WARNING !! No main config file found, using default config!
#
+ Creating chain cache directory /etc/dehydrated/chains
Processing odoo.gapl.com.tw
+ Creating new directory /etc/dehydrated/certs/odoo.gapl.com.tw ...
+ Signing domains...
+ Generating private key...
+ Generating signing request...
+ Requesting new certificate order from CA...
+ Received 1 authorizations URLs from the CA
+ Handling authorization for odoo.gapl.com.tw
+ 1 pending challenge(s)
+ Deploying challenge tokens...
+ Responding to challenge for odoo.gapl.com.tw authorization...
+ Challenge is valid!
+ Cleaning challenge tokens...
+ Requesting certificate...
+ Checking certificate...
+ Done!
+ Creating fullchain.pem...
+ Done!

如果沒有加入 NGINX 的 Virtual Host 設定,會出現 403 Forbidden 錯誤訊息

 #
 # !! WARNING !! No main config file found, using default config!
 #
 Processing www.gapl.com.tw
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 20 09:49:00 2017 GMT Certificate will expire
 (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for www.gapl.com.tw...
 + Responding to challenge for www.gapl.com.tw...
 ERROR: Challenge is invalid! (returned: invalid) (result: {
 "type": "http-01",
 "status": "invalid",
 "error": {
 "type": "urn:acme:error:unauthorized",
 "detail": "Invalid response from //odoo.gapl.com.tw/.well-known/acme-challenge/3EEdRHYvkAfx9uZSjV4h7FCfYMi7a6UlVnyuZudevtI: \"\u003c!DOCTYPE html\u003e \u003c!--[if lt IE 7 ]\u003e \u003chtml lang=\"zh\" id=\"top\" class=\"no-js ie6\"\u003e \u003c![endif]--\u003e \u003c!--[if IE 7 ]\u003e \u003chtml lang=\"zh\" id=\"\"",
 "status": 403
 },
 "uri": "//acme-v01.api.letsencrypt.org/acme/challenge/JqN-Fdoo3g23ltTm8D-itDtWz9rwQQYoJZbs7ZACt4g/1637437220",
 "token": "3EEdRHYvkAfx9uZSjV4h7FCfYMi7a6UlVnyuZudevtI",
 "keyAuthorization": "3EEdRHYvkAfx9uZSjV4h7FCfYMi7a6UlVnyuZudevtI.5nhCFdFDOMtHi0duVISKh5HbEpkCKimRes0pp1VRoLc",
 "validationRecord": [
 {
 "url": "//odoo.gapl.com.tw/",
 "hostname": "odoo.gapl.com.tw",
 "port": "443",
 "addressesResolved": [
 "60.251.46.241"
 ],
 "addressUsed": "60.251.46.241",
 "addressesTried": []
 },
 {
 "url": "//odoo.gapl.com.tw/.well-known/acme-challenge/3EEdRHYvkAfx9uZSjV4h7FCfYMi7a6UlVnyuZudevtI",
 "hostname": "odoo.gapl.com.tw",
 "port": "80",
 "addressesResolved": [
 "60.251.46.241"
 ],
 "addressUsed": "60.251.46.241",
 "addressesTried": []
 }
 ]
 })

接著修改 NGINX 設定檔的 SSL 設定

cp /etc/nginx/conf.d/odoo.gapl.com.tw.conf /etc/nginx/conf.d/odoo.gapl.com.tw.ssl.conf
vim /etc/nginx/conf.d/odoo.gapl.com.tw.ssl.conf

加入這兩行

ssl_certificate /etc/dehydrated/certs/odoo.gapl.com.tw/fullchain.pem;
ssl_certificate_key /etc/dehydrated/certs/odoo.gapl.com.tw/privkey.pem;

重新載入 NGINX 設定

systemctl reload nginx

清除 OPCache(不確定是否需要執行)

//www.gapl.com.tw/resetopc.php

記得確認 SSL 憑證失效日是否有成功延後喔!

自動展期

我們可以利用 cron 這個小程式來定期自動展期,首先編輯 crontab 設定檔

vim /etc/crontab

加入這兩行(於每周六 AM 3:00 檢查是否需要展期,AM 3:05 reload NGINX)

00 3 * * 6 root /etc/dehydrated/dehydrated -c -d www.gapl.com.tw
05 3 * * 6 root systemctl reload nginx.service

重新啟動 cron service

systemctl restart crond.service

完成!

番外篇

公司 Magento 網站一直以來都是使用 certbot,但不知為何,無法繼續使用 certbot 來 renew

以下是將現有的憑證轉用 dehydrated 來 renew 的紀錄

建立憑證資料夾

mkdir -p /etc/dehydrated/certs/www.gapl.com.tw/

複製現有憑證至 dehydrated 憑證資料夾

cp /etc/letsencrypt/live/www.gapl.com.tw/*.pem /etc/dehydrated/certs/www.gapl.com.tw/

Renew

/etc/dehydrated/dehydrated -c -d www.gapl.com.tw

成功的話會有下列訊息

[root@www html]# /etc/dehydrated/dehydrated -c -d www.gapl.com.tw
 #
 # !! WARNING !! No main config file found, using default config!
 #
 Processing www.gapl.com.tw
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Aug 20 09:49:00 2017 GMT Certificate will expire
 (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for www.gapl.com.tw...
 + Responding to challenge for www.gapl.com.tw...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!

接著修改 NGINX 設定檔的 SSL 設定

vim /etc/nginx/conf.d/www.gapl.com.tw.ssl.conf

將這兩行

ssl_certificate /etc/dehydrated/certs/www.gapl.com.tw/fullchain.pem;
 ssl_certificate_key /etc/dehydrated/certs/www.gapl.com.tw/privkey.pem;

修改為

ssl_certificate /etc/letsencrypt/live/www.gapl.com.tw/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/www.gapl.com.tw/privkey.pem;

重新載入 NGINX 設定

systemctl reload nginx
確認 CentOS 防火牆是否開放 HTTPS 服務
[root@localhost conf.d]# firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: ens160
sources:
services: ssh dhcpv6-client http
ports: 8069/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
開放 HTTPS 服務
[root@localhost conf.d]# firewall-cmd --permanent --zone=public --add-service=https
success
[root@localhost conf.d]# firewall-cmd --reload
success
再次確認防火牆是否開啓 HTTPS 服務
[root@localhost conf.d]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens160
  sources:
  services: ssh dhcpv6-client http https
  ports: 8069/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

記得確認 SSL 憑證失效日是否有成功延後喔!

參考資料

//letsencrypt.tw

//www.sslshopper.com/ssl-checker.html

Leave A Comment?