縮網址服務實作記錄 (2) - 基於 Docker 的 Let's Encrypt 申請與設定

Last updated on

縮網址服務為 https://url-ins.com/shorten/ 🔗 ,有任何想法或回饋,可以在 SurveyCake 🔗 留下寶貴的意見。(為了維持主機的維運,在頁面內放入 Google Adsense 廣告。)

縮網址服務實作記錄(1) - 基於 Docker 容器技術的網站服務架構實踐 中,已經完成基本服務的建立。

為了確保服務站台的可靠性與提升 SEO。接下來,就是要為服務站台增加 HTTPS 的 SSL/TLS 憑證保護。

Let's Encrypt 提供的免費的 SSL/TLS 憑證,雖然說有 3 個月的時間限制。但只要配合 Certbot 來協助 SSL/TLS 憑證申請與更新,就可以為站台提供更可靠的保護。

有趣的是,在研究與尋找如何進行 Ngnix 與 Let’s Encrypt 設定的過程,無意中發現 Traefik 🔗。一套高度支援 Dockr ,與 Ngnix 相似的反向代理工具(Reverse Proxy),後續有機會使用,也會隨手記錄操作筆記。

在本篇文章中,主要是在討論以下的項目

  • 如何為 Container 內的 NGINX 進行 Let’s Encrypt 的設定。
  • 使用 Certbot 官方提供的 docker Image 來申請 SSL/TLS 憑證。
  • Docker 的 Volume 的用法。

前言

在完成服務的架設後,已經可以使用 HTTP ,經由 Domain 連線到服務站台。再進一步,我們要藉由 SSL/TLS 憑證來提升服務站台的可靠性與安全性。

當然,我們可以選擇收費的憑證頒發機構(Certificate Authority, CA),例如 TWCA、Sectigo、Certum 等等。在成本的考量下,選擇使用 Let’s Encrypt 🔗 提供的 SSL/TLS 憑證。

在 Let’s Encrypt 的官方文件 🔗,也推薦使用 Certbot 來協助取得與安裝憑證。若是不符合需求,也有列出其他類型的工具。

額外補充,只要有實作 ACME (Automatic Certificate Management Environment 🔗) 協定的工具,都可以跟 Let’s Encrypt 申請 SSL/TLS 憑證。

ACME 的驗證方式,可以進一步查看 Let’s Encrypt 提供的 ACME 驗證方式 🔗 說明。

當 Nginx 直接安裝在 Ubuntu 主機,可以參考 NGINX 官方 Blog 說明 🔗,直接依據下列步驟,進行 Certbot 的安裝與 SSL/TLS 憑證的申請。

另外,由於 Certbot 已經整合 NGNX,可以使用 certbot --nginx 指令,自動更新 Nginx 組態,請求證書。也可以加上 certonly 參數,讓 certbot 只是單純申請 SSL/TLS 憑證,

# 安裝 Certbot
sudo apt-get update
sudo apt-get install certbot
sudo apt-get install python3-certbot-nginx

# 使用 Certbot 自動進行 NGINX 設定
sudo certbot --nginx -d example.com -d www.example.com

certbot 跟 Let’s Encrypt 申請的 SSL/TLS 憑證,會存放在 /etc/letsencrypt/live/{網域}

但是…

在將 NGINX 與靜態網站打包為 Docker Image 的前提下,若是在 Container 進行上述的設定,當更新 Docker Image 的版本時,會再建立一組新的 Container。此時需要再重新進行一次設定。

在接下來,我會記錄使用 Docker Mount/Volume 機制來保存 SSL/TLS 憑證,或是直接使用 Certbot 類似,但已經被包為 Docker Image 的工具,來協助進行設定。

基於 NGINX 的憑證申請與設定

1. 使用 Certbot --webroot 配合 Mount 來設定 SSL/TLS 憑證

首先,在 Ubuntu 主機安裝 certbot 套件。

# 安裝 Certbot
sudo apt-get update
sudo apt-get install certbot
sudo apt-get install python3-certbot-nginx

使用 --webroot 進行 Let’s Encrypt 憑證申請,需要指定網站的根目錄。

為此,需要調整 docker-compose.yamlnginx.conf 兩個部份。

  1. 調整 docker-compose.yaml 檔內 volumes 的設定, 增加 certbot --webroot 使用的資料夾與 Container 內的目錄對應。

雖然我們是用 --webroot 的方法,但在 docker-compose.yml 千萬不要直接指定站台根目錄。這會導制站台直接出現 404 錯誤。

我們建立了一個 letsencrypt-site 的資料夾,以便 Certbot 存放 Let’s Encrypt 驗證用的資料檔案。並讓它對應到 Container 內的 /user/share/nginx/html/acme

version: '3'

services:

  web:
    image: registry.gitlab.com/url-insight/url-insight/web:latest
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./letsencrypt-site:/usr/share/nginx/html/acme # --webroot 使用
    networks:
      -  gateway-web

networks:
  gateway:
    external: true
  1. 設定 nginx.conf,讓 /.well-known/acme-challenge 可以指向 Container 內,存放 Let’s Encrypt 驗證資料的檔案目錄。
server {
    listen 80;
    listen [::]:80;
    server_name url-ins.com;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html/acme;
    }

    root /usr/share/nginx/html;
    index index.html;
}

再完成上述的兩個設定後,就可以使用 certbot certonly --webroot 來申請憑證。

# 使用 --webroot 的方式
sudo certbot certonly --webroot -w ./letsencrypt-site -d url-ins.com
certbot certonly --webroot
certbot certonly --webroot

此時,fullchain.pemprivkey.pem 是存放在 Ubuntu 主機的 /etc/letsencrypt/live 目錄下。

將 SSL/TLS 憑證掛載到 Container

接下來,就是進行 HTTPS 的 SSL/TLS 憑證設定了。

為了讓 Container 可以使用剛剛申請的憑證,就必須將憑證所在的資訊夾,掛載到 Container 中。

有兩種作法可以選擇。

  • 直接將 /etc/letsencrypt/live 目錄掛載到 Container 。
  • 將憑證先放到 volume 之中,再把掛載 volume 到 Container。
直接掛載 /etc/letsencrypt/live 內 SSL/TLS 憑證。
version: '3'

services:

  web:
    image: registry.gitlab.com/url-insight/url-insight/web:latest
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./letsencrypt-site:/usr/share/nginx/html/acme
      - /etc/letsencrypt:/etc/letsencrypt # 直接掛載 for Let's Encrypt certificates
    networks:
      -  gateway-web

networks:
  gateway:
    external: true
將 SSL/TLS 憑證放到 Docker Volume 後再掛載
  • 增加 Docker Volume 來存放 certbot 順利取回的 SSL/TLS 憑證。
# 建立 Docker Volume
sudo docker volume create {volume_name}

接著把 SSL/TLS 憑證放到 volume 之中。

此時,我們需要先掛載 volume,才能把 SSL/TLS 憑證放到 volume。可以直接把 volume 掛到 docker-compose.yml 後,進行複制 SSL/TLS 憑證的動作。

不過,為了方便理解,使用 busybox 掛載剛剛建立出來的 volume。

# 建立 Volume
sudo docker volume create letsencrypt-certs

# 掛載 volume 到 busybox 內
sudo docker run -v letsencrypt-certs:/mnt --name test-busybox busybox

# 複製 /etc/letsencrypt/ 目錄到 busybox Container 的根目錄
sudo docker cp /etc/letsencrypt test-busybox:/mnt

簡單說明上述的指令。

  • 使用 docker volume create 來建立一個空的 Docker volume。
  • docker run 時,使用 -v 來掛載 Docker volume,並宣告建立出來的 Container name 為 testbusybox
  • 最後,使用 docker cp 來進行資料夾的複製。
複製 /etc/letsencrypt 內的資訊
複製 /etc/letsencrypt 內的資訊

當然,如果要確認 volume 是否有資料,可以再建一個臨時 Container 來進行查看。

sudo docker run -it --rm -v letsencrypt-certs:/mnt busybox
建立一個臨時 Container 來確認 volume 內容
建立一個臨時 Container 來確認 volume 內容

再完成將 *.pem 複製到 volume 的動作後,就是把 volume 掛載到 NGINX 所在的 Container 中。

調整後的 docker-compose.yml 如下。

version: '3'

services:

  web:
    image: registry.gitlab.com/url-insight/url-insight/web:latest
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./letsencrypt-site:/usr/share/nginx/html/acme # --webroot 使用
      - letsencrypt-certs:/etc/letsencryptexit # for Let's Encrypt certificates
    networks:
      -  gateway-web

volumes:
	letsencrypt-certs: # Define the volume for Let's Encrypt certificates
		external: true

networks:
  gateway:
    external: true

進行 nginx.conf 的 HTTPS 設定

在完成 SSL/TLS 憑證申請後,接下來就是進行 nginx.conf 的調整,加入 443 的 HTTPS 設定。並將 HTTP 的請求,永久轉址到 HTTPS。


http {
 server{
    listen 80;
    listen [::]:80;

    server_name url-ins.com www.url-ins.com;
    server_tokens off;

    location / {
      return 301 https://$host$request_uri;
    }
  }

  server {
    listen 443 default_server ssl http2;
    listen [::]:443 ssl http2;

    server_name url-ins.com www.url-ins.com;

    ssl_protocols   TLSv1.2 TLSv1.3;
    ssl_certificate /etc/letsencrypt/live/url-ins.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/url-ins.com/privkey.pem;

}

在完成設定後,別忘了讓 NGINX 重新載入 nginx.conf 的設定。

2. 使用 Certbox 官方的 Docker Image

若是不想要在 Ubuntu 主機內,安裝 certbot,也可以選擇使用 Docker Hub 的 certbot/certbot 🔗 來協助申請 SSL/TLS 憑證。

在 Certbot 的官方說明文件 Get Certbot — running-with-docker 🔗 也有詳細的操作說明。

sudo docker run -it --rm --name certbot \
            -v "/etc/letsencrypt:/etc/letsencrypt" \
            -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
            certbot/certbot certonly

簡單說明一下上述的指令意思。

  • 使用 certbot/certbot 的 Docker Image,建立一個用完就刪除的 Container。
  • 啟動 Container 時,同時傳入 certonly 的參數。
  • 掛載 /etc/letsencrypt/var/lib/letsencrypt 對應的資料夾。

/var/lib/letsencrypt 用於存放 .well-known/acme-challenge 的所有 HTTP 請求,而 /etc/letsencrypt 則是存放 Let’s Encrypt 發放的 SSL/TLS 憑證。

How to handle HTTPS using Nginx, Let’s encrypt and Docker - Mindsers Blog 🔗 這篇,作者直接使用 docker compose 來完成 certbox 與 nginx 的整合。內容寫的還滿清楚的,值得一看。

不過,因為我個人想要維持 dokcer-compose.yml 的單純,所以把 Certbot Docker Image 的操作拆分。

動作步驟如下。

  • 建立 Certbot 與 docker-compose.yml 共用的 docker volume。
  • 調整 docker-compose.yml 中,掛載 docker volume。
  • 調整 NGINX 使用的 nginx.conf。
  • 建立並運行 Certbot 的 Container。

首先,建立存放 Let’s Encrypt .well-known/acme-challenge 驗證資料與發送 SSL/TLS 憑證的 docker volume。

# 存放 Let's Encrypt 發放的 SSL/TLS 憑證
sudo docker volume create letsencrypt-certs

# 存放 Let's Encrypt acme-challenge 驗證資料
sudo docker volume create letsencrtpt-acme

接著,調整 docker-compose.yml,將 letsencrypt-certsletsencrtpt-acme 兩個 docker volume 掛上去。

version: '3'

services:

  web:
    image: registry.gitlab.com/url-insight/url-insight/web:latest
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - letsencrtpt-acme:/usr/share/nginx/html/acme # --webroot 使用
      - letsencrypt-certs:/etc/letsencrypt # for Let's Encrypt certificates
    networks:
      -  gateway-web

volumes:
	letsencrypt-certs: # Define the volume for Let's Encrypt certificates
		external: true
	letsencrtpt-acme:
		external: true

networks:
  gateway:
    external: true

調整完 docker-compose.yml 後,接著來調整 NIGIX 的設定。

在這邊,ssl_certificatessl_certificate_key 預設使用 Let’s Encrypt SSL/TLS 的資料夾位置。實務上,可以依自行規劃進行調整指定的位置。

http {
 server{
    listen 80;
    listen [::]:80;

    server_name url-ins.com www.url-ins.com;
    server_tokens off;

    location / {
      return 301 https://$host$request_uri;
    }
  }

  server {
    listen 443 default_server ssl http2;
    listen [::]:443 ssl http2;

    server_name url-ins.com www.url-ins.com;

    ssl_protocols   TLSv1.2 TLSv1.3;
    ssl_certificate /etc/letsencrypt/live/url-ins.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/url-ins.com/privkey.pem;
}

完成前面的設定後,就是使用 docker compose up 把 NGINX 站台啟動。

接著啟動 Certbot 的 Containr,進行 Let’s Encrypt 的 SSL/TLS 憑證申請。

sudo docker run -it --rm --name certbot \
            -v "letsencrypt-certs:/etc/letsencrypt" \
            -v "letsencrypt-acme:/var/lib/letsencrypt" \
            certbot/certbot certonly --webroot \
            -w "/var/lib/letsencrypt" \
            -d url-ins.com

完成後,就完成了 SSL/TLS 憑證的申請作業了。

補充資料

▶ 站內文章

▶ 外部文章

中文資源

英文資源


Series
縮網址服務實作記錄