traefik & let’s encrypt
前言
在上一篇文章中介紹如何設置 reverse proxy ,這篇將會介紹如何使用 let’s encrypt 讓 traefik 支援 HTTPS 連線。
簡單介紹 let’s encrypt
let’s encrypt 是個憑證頒發機構,與其他憑證頒發機構不同的是 let’s encrypt 提供免費的憑證,只要客戶端達成某些條件,向 let’s encrypt 證明其擁有某個網域名時,let’s encrypt 就會免費提供數位憑證給客戶端。
traefik & let’s encrypt
traefik 本身支援使用最常見的 TLS 憑證,也支援透過 ACME 的方式向支援 ACME 頒發憑證的機構自動獲取數位憑證(此範例使用 let’s encrypt)。此外,let’s encrypt 所頒發的數位憑證有有效期限,traefik 會在到期時自動更新數位憑證。
let’s encrypt 運作機制
在申請憑證時,最重要的步驟就是向 let’s encrypt 證明你擁有此網域。let’s encrypt 有提供三種方式:
- HTTP-01 考驗:let’s encrypt 會給客戶端一個 token ,客戶端要將 此 token 放在網頁伺服器
http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>
中,let’s encrypt 之後就會向該網址發送請求,若 let’s encrypt 成功拿到 token 後就會認定此網域的確為客戶所擁有,並頒發數位憑證。 - DNS-01 考驗:let’s encrypt 會給客戶端一組字串 ,客戶端將此字串以 TXT 紀錄放在 DNS 中,接著 let’s encrypt 就會去查詢相對應的 DNS TXT 紀錄。若有成功查詢到 TXT 紀錄,就會認定此網域的確為客戶所擁有,並頒發數位憑證。
- TLS-ALPN-01 考驗:此方法較為少見,詳細可參考官網。
traefik 支援以上三種驗證方式,且會在快到期時自動更新憑證。接下來的範例中會使用 HTTPS-01 以及 DNS-01 考驗。
traefik 設定範例
以下文章將會接續上一篇文章,設置 whoami 以及 podinfo 使我們能透過 HTTPS 連線。
在開始教學前,請先確認你的環境滿足以下條件
- 可以使用 Docker 以及 Docker-Compose
- 擁有一個 domain name
- 確保 port 80、443 開啟且並沒有被其他程式使用
準備步驟
traefik 是透過 ACME 的方式去獲取憑證,所以我們要事先準備好一個檔案存放這些憑證。
建立
acme.json
檔案延續上一篇文章,我們在 traefik-example 目錄中建立一個空的 acme.json 檔案
touch acme.json
接著將他的權限改為 600 (只有擁有者有讀寫權限)
chmod 600 acme.json
將此檔案 mount 到 traefik container 中
docker-compose.yaml
version: "3.8" services: traefik: image: "traefik:v2.5" container_name: "traefik" ports: - "80:80" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yaml:/traefik.yaml:ro" - "./acme.json:/acme.json" ## 以下省略...
當我們設定好 HTTPS 後使用者會通過 port 443 與 traefik 連線,所以我們先在 docker-compose 中打開 port 443
打開 port 443
docker-compose.yaml
version: "3.8" services: traefik: image: "traefik:v2.5" container_name: "traefik" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yaml:/traefik.yaml:ro" - "./acme.json:/acme.json" ## 以下省略...
別忘了新增一個 entrypoint
新增 “websecure” entrypoint
traefik.yaml
entryPoints: web: address: ":80" websecure: address: ":443"
透過 HTTP-01 考驗
設置 certificates resolvers
以下範例設置名稱為
lets-encrypt-resolver
的 certificates resolvers ,並指定其驗證方法為 HTTP-01 考驗,且儲存憑證的檔案名為acme.json
。traefik.yaml
entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: lets-encrypt-resolver: # <- 這邊為使用者自己定義的名稱 acme: #caServer: <https://acme-staging-v02.api.letsencrypt.org/directory> storage: acme.json email: [email protected] # 這邊寫自己常用的 email 信箱,當憑證快到期時就會提醒你 httpChallenge: entryPoint: web
這邊需要注意的是因為我們使用 HTTP-01 考驗
entryPoint
這邊一定要設置為 port 80 的 entrypoint 。traefik 的
caServer
預設為*<https://acme-v02.api.letsencrypt.org/directory
> 若改成*https://acme-staging-v02.api.letsencrypt.org/directory
則 traefik 就會頒發測試用憑證。設置 whoami podinfo
當我們設置完 certificates resolvers 後,需要指定 router 使用 certificates resolvers ,讓所有進入到此 router 的 https request 能夠成功解密。
以下範例將名稱為
whoami-router
的 router 設定其 certificates resolvers 為lets-encrypt-resolver
docker-compose.yaml
version: "3.8" services: traefik: image: "traefik:v2.5" container_name: "traefik" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yaml:/traefik.yaml:ro" - "./acme.json:/acme.json" whoami: image: "traefik/whoami" container_name: "whoami" labels: - "traefik.enable=true" - "traefik.http.routers.whoami-router.entrypoints=web" - "traefik.http.routers.whoami-router.rule=Host(`whoami.$MY_DOMAIN`)" # 在此範例相當於 "whoami.ainimal.io" - "traefik.http.services.whoami-service.loadbalancer.server.port=80" - "traefik.http.routers.whoami-router.service=whoami-service" - "traefik.http.routers.whoami-router.tls.certresolver=lets-encrypt-resolver" ## 以下省略...
別忘了將 whoami container 的 entrypoint 改成 https (範例為:
websecure
)version: "3.8" services: traefik: image: "traefik:v2.5" container_name: "traefik" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yaml:/traefik.yaml:ro" - "./acme.json:/acme.json" whoami: image: "traefik/whoami" container_name: "whoami" labels: - "traefik.enable=true" - "traefik.http.routers.whoami-router.entrypoints=websecure" - "traefik.http.routers.whoami-router.rule=Host(`whoami.$MY_DOMAIN`)" # 在此範例相當於 "whoami.ainimal.io" - "traefik.http.services.whoami-service.loadbalancer.server.port=80" - "traefik.http.routers.whoami-router.service=whoami-service" - "traefik.http.routers.whoami-router.tls.certresolver=lets-encrypt-resolver" ## 以下省略...
透過 DNS-01 考驗
透過 DNS-01 考驗申請憑證的好處就是 DNS-01 考驗支援 wild card 憑證,舉例來說如果我申請了 *.ainimal.io 的憑證,podinfo.ainimal.io、whoami.ainimal.io 就可以直接使用,不需要另外申請。
在設置前請先確認你的 DNS 機構是否在支援名單中。
設置 certificates resolvers
以下範例設置名稱為
lets-encrypt-resolver
的 certificates resolvers ,並指定其驗證方法為 DNS-01 考驗,且儲存憑證的檔案名為acme.json
。traefik.yaml
entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: lets-encrypt-resolver: # <- 這邊為使用者自己定義的名稱 acme: #caServer: <https://acme-staging-v02.api.letsencrypt.org/directory> storage: acme.json email: [email protected] # 這邊寫自己常用的 email 信箱,當憑證快到期時就會提醒你 dnsChallenge: provider: cloudflare resolvers: - "1.1.1.1:53" - "8.8.8.8:53"
這邊需要注意的是要將
provider
設定為自己的 DNS 機構。設置 DNS-01 考驗所需要的環境變數
traefik 在執行 DNS-01 考驗時,是透過 API 的方式去更改 DNS TXT 紀錄,所以我們要提供 DNS 機構的 API token 等相關資訊給 traefik 。請參考支援名單中每個 provider 所需要的環境變數名稱,traefik 會根據你設定的 provider 從環境變數中獲取資訊。
以下範例使用 cloudflare 作為 provider ,需要
CF_API_EMAIL
CF_API_KEY
環境變數.env
MY_DOMAIN=ainimal.io DEFAULT_NETWORK=mynetwork CF_API_EMAIL=[email protected] CF_API_KEY=93klas1ks93cnqi22kk8fk
設置 whoami podinfo
當我們設置完 certificates resolvers 後,需要指定 router 使用 certificates resolvers ,讓所有進入到此 router 的 https request 能夠成功解密。
以下範例將名稱為
whoami-router
的 router 設定其 certificates resolvers 為lets-encrypt-resolver
docker-compose.yaml
version: "3.8" services: traefik: image: "traefik:v2.5" container_name: "traefik" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yaml:/traefik.yaml:ro" - "./acme.json:/acme.json" whoami: image: "traefik/whoami" container_name: "whoami" labels: - "traefik.enable=true" - "traefik.http.routers.whoami-router.entrypoints=websecure" - "traefik.http.routers.whoami-router.rule=Host(`whoami.$MY_DOMAIN`)" # 在此範例相當於 "whoami.ainimal.io" - "traefik.http.services.whoami-service.loadbalancer.server.port=80" - "traefik.http.routers.whoami-router.service=whoami-service" - "traefik.http.routers.whoami-router.tls.certresolver=lets-encrypt-resolver" ## 以下省略...
若我們想要用到 DNS-01 考驗才有的功能 wild card 憑證就會需要修改 entrypoint 的 tls 設定,此處的 tls 設定為預設設定,若使用者在 router 中有自定義 tls 設定則會自動忽略此設定。
修改 entrypoint 設定
traefik.yaml
entryPoints: web: address: ":80" websecure: address: ":443" http: tls: certResolver: "lets-encrypt-resolver" domains: - main: "yungen.me" sans: - "*.yungen.me" certificatesResolvers: lets-encrypt-resolver: acme: #caServer: <https://acme-staging-v02.api.letsencrypt.org/directory> storage: acme.json email: [email protected] # 這邊寫自己常用的 email 信箱,當憑證快到期時就會提醒你 dnsChallenge: provider: cloudflare resolvers: - "1.1.1.1:53" - "8.8.8.8:53"
設置 whoami podinfo
當我們設置過預設 tls 後就不需要再特別設定 tls 了。
docker-compose.yaml
version: "3.8" services: traefik: image: "traefik:v2.5" container_name: "traefik" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yaml:/traefik.yaml:ro" - "./acme.json:/acme.json" whoami: image: "traefik/whoami" container_name: "whoami" labels: - "traefik.enable=true" - "traefik.http.routers.whoami-router.entrypoints=websecure" - "traefik.http.routers.whoami-router.rule=Host(`whoami.$MY_DOMAIN`)" # 在此範例相當於 "whoami.ainimal.io" - "traefik.http.services.whoami-service.loadbalancer.server.port=80" - "traefik.http.routers.whoami-router.service=whoami-service" ## 以下省略...