Let's Encrypt憑證申請

使用容器化的Nginx與Certbot

June 16, 2023, 1:35 a.m.
網站設計

在處理EC2上面的HTTPS設定的時候,雖然AWS有提供憑證管理的服務ACM,但因為ACM並不允許使用者把它所頒發的憑證直接裝在架設於EC2的私有服務上面,所以更常聽到的替EC2設定HTTPS的做法,其實是透過將EC2部屬於一個跟ACM關聯起來的ALB後面。

我自己架設的一些服務是將Nginx, Application容器化後部署於一台EC2上,在沒辦法使用ACM憑證的前提下,就需要另覓其他的方法。

Let’s Encrypt是一個免費開放的自動化憑證頒發機構,他的目標是透過ACME協定在不需要人力的情況下,可以讓網頁伺服器自動取得瀏覽器可信任的憑證。

這篇筆記記錄了如何使用他的第三方憑證申請客戶端程式Certbot的Docker映像檔,透過提供驗證檔案的方式,申請憑證給容器化的Nginx使用。

let's encrypt intro
他的主要流程為:
1. 伺服器上的憑證管理軟體(也就是Certbot)會對Let’s Encrypt發出要申請xxx.com的請求。
2. Let’s Encrypt要求憑證管理軟體「做到某些事情」來證明自己對xxx.com網域具有控制的能力。
- 設定DNS紀錄
- 在網站上新增一個提供檔案的路徑 (這篇筆記使用的方法)
3. 憑證裡軟體完成這些任務後,會請Let’s Encrtpy CA來檢驗
4. 檢驗成功後,憑證管理軟體就可以使用授權過的金鑰,對Let’s Encrypt CA來提出憑證的申請、更新、註銷。

Docker Compose設定

這邊使用Docker-Compose搭起一個Nginx與Certbot的容器。
(Certbot並不會像Nginx一樣被作為一個服務叫起來,而是會以指令的形式來使用它)

version: '3'

services:
  server:
    container_name: "server"
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - {想掛入Nginx容器的config檔案路徑}:/etc/nginx/
      - ./certbot/www:/var/www/certbot/:ro
      - ./certbot/conf/:/etc/nginx/ssl/:ro
      - ./certbot/archive:/etc/nginx/archive/:ro
  certbot:
    image: certbot/certbot:latest
    volumes:
      - ./certbot/www/:/var/www/certbot/:rw
      - ./certbot/conf/:/etc/letsencrypt/live:rw
      - ./certbot/archive:/etc/letsencrypt/archive:rw

volumes-structure
- volumes關係示意圖

Volumes的第一行設定是有關於NginX Config的位置,因為Nginx支援Config的hot reload,可以直接把想要使用的設定從外面掛進去容器讓它生效。稍後會把寫了Let’s Encrypt要驗證的Http檔案路徑的設定檔放在這裡。

第二行之後的設定,可以跟下面的Certbot的volumes一起配對著看,這邊使用一個與Docker Compose同路徑的./certbot資料夾做範例,把該目錄與其下的子目錄分別掛給Nginx與Certbot的服務:

[Nginx Container]        [Host Machine]    [Certbot Container]
/var/www/certbot/ <--> ./certbot/www <--> /var/www/certbot/
/etc/nginx/ssl <--> ./certbot/conf/ <--> /etc/letsencrypt/live
/etc/nginx/archive <--> ./certbot/archive/ <--> /etc/letsencrypt/archive
  1. ./certbot/www:Certbot會把產生給Let’s Encrypt驗證的檔案放在這個目錄下。這個目錄會被另外被掛進去Nginx的/var/www/certbot,然後Nginx的Config會把要給Let’s Encrypt驗證的網站路徑(/.well-known/acme-challenge/)指向這個目錄。
  2. ./certbot/conf :Certbot會把產生的憑證放在/etc/letsencrpyt/live這個目錄下,但需要注意的是這裡的憑證檔案其實都是軟連結,他們其實都是指向放置在/etc/letsencrpyt/archive路徑下的檔案。
  3. ./certbot/archive:因此基於上述的理由,我們也需要把/etc/letsencrypt/archive掛出去到Nginx的目錄下面,Nginx才能讀取對應的憑證檔案。

Nginx.conf的設定

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;

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

        server_name xxx.com;

        charset utf-8;
        client_max_body_size 75M;

        location /.well-known/acme-challenge/ {
            root /var/www/certbot;
        }

        # Redirect all HTTP traffic to HTTPS
        location / {
            return 301 https://$server_name$request_uri;
        }
    }

    server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name xxx.com;

        # SSL configuration
        ssl_certificate /etc/nginx/ssl/xxx.com/fullchain.pem;
        ssl_certificate_key /etc/nginx/ssl/xxx.com/privkey.pem;

        charset utf-8;
        client_max_body_size 75M;

        location / {
            ...看原本的網站指向哪裡...
        }
    }
}

Nginx定義兩個Server Block,分別監聽80, 443port的請求,

Server Block 80 Port

我們需要在這個Block定義好,要讓Let’s Encrypt來驗證檔案的路徑,也就是/.well-known/acme-challenge,這個路徑會指向剛剛我們在docker-compose所掛載的volumevar/www/certbot。然後我們把其他的請求全部轉給監聽443 Port的block。

Server Block 443 Port

ssl_certificate以及ssl_certificate_key分別去剛剛掛載的路徑/etc/nginx/ssl下面取得憑證與私鑰。

Certbot指令

憑證申請

docker-compose.yml與nginx.conf都處理好之後,就可以準備來使用申請憑證的指令。這邊我們指定使用--webroot的方式,讓Let’s Encrypt CA透過檢查目錄下的檔案是否合法。-d參數則是指定了我們要替xxx.com網域申請憑證。

docker-compose run --rm certbot certonly --webroot --webroot-path /var/www/certbot/ -d xxx.com

中間Certbot會問一些跟註冊信箱,ToS有關的訊息,按他指示的步驟完成後應該會出現類似下面的訊息:

....
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/xxx.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/xxx.com/privkey.pem
This certificate expires on ~~~~
...

可以檢查Host Machine的./certbot/conf目錄,看一下憑證是否有出現。
重新啟動Nginx的服務之後,應該就可以看到伺服器能處理HTTPS的請求。

Tags:

Nginx
HTTPS