Let's Encrypt 證書,HTTP challenge
LE
- Let's Encrypt. 提供免費證書的服務Certificate
- 存儲在服務器文件中的加密密鑰,允許進行加密通信並確認身份ACME
- 一種協議(精確商定的通信方式),以協商來自 LE 的證書。它是 traefik 的一部分。DNS
- 互聯網上的服務器,將域名轉換為 IP 地址
Traefik 使用 ACME 向 LE 請求特定域的證書,如 example.com
。LE 用一些隨機生成的文本來回答,然後 traefik 把這些文本放在服務器的特定位置。然後,LE 向 DNS 互聯網服務器詢問 example.com
,結果指向了某個 IP 地址。LE 通過端口 80/443 查找該 IP 地址,查找包含該隨機文本的文件。
如果存在,那麼這證明了要求證書的人都控制了服務器和域,因為它顯示了對 DNS 記錄的控制權。證書已頒發,有效期為 3 個月,traefik 將在少於 30 天的時間內自動嘗試續訂。
現在我們來看看該怎麼做。
創建一個具有 600 權限的空 acme.json 文件
該文件將存儲證書以及有關證書的所有信息。
touch acme.json && chmod 600 acme.json
在 traefik.yml 中添加 443 入口點和證書解析器
在 entrypoint 部分中,新的 entrypoint 被添加為 websecure,端口 443
certificatesResolvers 是一個配置部分,它告訴 traefik 如何使用 acme resolver 獲取證書。
certificatesResolvers: lets-encr: acme: #caServer: https://acme-staging-v02.api.letsencrypt.org/directory storage: acme.json email: [email protected] httpChallenge: entryPoint: web
- 解析器的名稱為
lets-encr
,並使用 acme - 註釋掉了 staging caServer 使 LE 頒發了一個 staging 證書,這是一個無效的證書,不會給綠鎖,但沒有限制,所以很適合測試。如果它在工作,它會說,我們加密。
- Storage 告訴在哪裡存儲給定的證書 -
acme.json
- 郵件是 LE 發送證書過期通知的地方
- httpChallenge 有一個入口點,因此 acme 在端口 80 上執行 http challenge
這就是 acme 所需要的一切
traefik.yml
## STATIC CONFIGURATION log: level: INFO api: insecure: true dashboard: true entryPoints: web: address: ":80" websecure: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false certificatesResolvers: lets-encr: acme: #caServer: https://acme-staging-v02.api.letsencrypt.org/directory storage: acme.json email: [email protected] httpChallenge: entryPoint: web
暴露/映射端口 443 並將 acme.json 掛載在 traefik-docker-compose.yml 中
注意:acme.json 不是 :ro
- 只讀
traefik-docker-compose.yml
version: "3.7" services: traefik: image: "traefik:v2.1" container_name: "traefik" hostname: "traefik" env_file: - .env ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yml:/traefik.yml:ro" - "./acme.json:/acme.json" networks: default: external: name: $DEFAULT_NETWORK
向容器添加所需的標籤
與第一章中的純 HTTP 相比,它只是將路由器的入口點從 web
更改為 websecure
, 並將名為 lets-encr
的證書解析器分配給現有路由器
whoami-docker-compose.yml
version: "3.7" services: whoami: image: "containous/whoami" container_name: "whoami" hostname: "whoami" labels: - "traefik.enable=true" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.rule=Host(`whoami.$MY_DOMAIN`)" - "traefik.http.routers.whoami.tls.certresolver=lets-encr" networks: default: external: name: $DEFAULT_NETWORK
nginx-docker-compose.yml
version: "3.7" services: nginx: image: nginx:latest container_name: nginx hostname: nginx labels: - "traefik.enable=true" - "traefik.http.routers.nginx.entrypoints=websecure" - "traefik.http.routers.nginx.rule=Host(`nginx.$MY_DOMAIN`)" - "traefik.http.routers.nginx.tls.certresolver=lets-encr" networks: default: external: name: $DEFAULT_NETWORK
運行容器
稍等一分鐘
容器現在只能在 https 上工作並且具有 greenlock
檢查 acme.json 的內容
如果要重新開始,請刪除acme.json
Let's Encrypt 證書在 cloudflare 上 DNS challenge
LE
- Let's Encrypt. 提供免費證書的服務Certificate
- 存儲在服務器文件中的加密密鑰,允許進行加密通信並確認身份ACME
- 一種協議(精確商定的通信方式),以協商來自 LE 的證書。它是 traefik 的一部分。DNS
- 互聯網上的服務器,將域名轉換為 IP 地址
Traefik 使用 ACME 向 LE 請求特定域的證書,如 example.com
。LE 用一些隨機生成的文本來回答,然後 traefik 把這些文本放在服務器的特定位置。然後,LE 向 DNS 互聯網服務器詢問 example.com
,結果指向了某個 IP 地址。LE 通過端口 80/443 查找該 IP 地址,查找包含該隨機文本的文件。
如果存在,那麼這證明了要求證書的人都控制了服務器和域,因為它顯示了對 DNS 記錄的控制權。證書已頒發,有效期為 3 個月,traefik 將在少於 30 天的時間內自動嘗試續訂。
與 httpChallenge 相比的好處是能夠使用通配符證書。這些是驗證所有子域 *.example.com
的證書 另外,無需打開任何端口。
但 traefik 需要能夠對 DNS 記錄進行自動更改,因此需要管理網站 DNS 的人對此提供支持。這就是為什麼選擇 cloudflare。
現在我們來看看該怎麼做。為所有規劃的子域添加類型 A DNS 記錄
[whoami, nginx, *] 是示例子域,每個子域都應有一個指向 traefik IP 的 A 記錄。
創建一個具有 600 權限的空 acme.json 文件
touch acme.json && chmod 600 acme.json
將 443 入口點和證書解析器添加到 traefik.yml
在 entrypoint 部分中,新的 entrypoint 被添加為 websecure,端口 443
certificatesResolvers 是一個配置部分,它告訴 traefik 如何使用 acme resolver 獲取證書。
certificatesResolvers: lets-encr: acme: #caServer: https://acme-staging-v02.api.letsencrypt.org/directory email: [email protected] storage: acme.json dnsChallenge: provider: cloudflare resolvers: - "1.1.1.1:53" - "8.8.8.8:53"
- 解析器的名稱為
lets-encr
,並使用 acme - 註釋掉了 staging caServer 使 LE 頒發了一個 staging 證書,這是一個無效的證書,不會給綠鎖,但沒有限制,所以很適合測試。如果它在工作,它會說,我們加密。
- Storage 告訴在哪裡存儲給定的證書 -
acme.json
- 郵件是 LE 發送證書過期通知的地方
- dnsChallenge 是由一個 provider 指定的,
在這個例子中是 cloudflare。每個提供程序在 .env 文件中需要不同名稱的環境變量, 但這是稍後的內容,這裡只需要提供程序的名稱
- 解析器是在挑戰期間使用的知名 DNS 服務器的 IP
traefik.yml
## STATIC CONFIGURATION log: level: INFO api: insecure: true dashboard: true entryPoints: web: address: ":80" websecure: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false certificatesResolvers: lets-encr: acme: #caServer: https://acme-staging-v02.api.letsencrypt.org/directory email: [email protected] storage: acme.json dnsChallenge: provider: cloudflare resolvers: - "1.1.1.1:53" - "8.8.8.8:53"
在 .env
文件中添加所需的變量
我們知道根據支持的提供商列表添加哪些變量
對於 cloudflare 變量是
CF_API_EMAIL
- cloudflare loginCF_API_KEY
- global api key
.env
MY_DOMAIN=example.com DEFAULT_NETWORK=traefik_net [email protected] CF_API_KEY=8d08c87dadb0f8f0e63efe84fb115b62e1abc
暴露/映射端口 443 並將 acme.json 掛載在 traefik-docker-compose.yml 中
注意:acme.json 不是 :ro
- 只讀
traefik-docker-compose.yml
version: "3.7" services: traefik: image: "traefik:v2.1" container_name: "traefik" hostname: "traefik" env_file: - .env ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yml:/traefik.yml:ro" - "./acme.json:/acme.json" networks: default: external: name: $DEFAULT_NETWORK
在容器上添加所需的標籤
與第一章中簡單的 http 相比
- 路由器的入口點從
web
切換到websecure
- 分配給路由器的名為
lets-encr
的證書解析器 - 定義將要獲得證書的主域的標籤,在這裡是 whoami.example.com,域名是從
.env
文件中提取的
whoami-docker-compose.yml
version: "3.7" services: whoami: image: "containous/whoami" container_name: "whoami" hostname: "whoami" labels: - "traefik.enable=true" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.rule=Host(`whoami.$MY_DOMAIN`)" - "traefik.http.routers.whoami.tls.certresolver=lets-encr" - "traefik.http.routers.whoami.tls.domains[0].main=whoami.$MY_DOMAIN" networks: default: external: name: $DEFAULT_NETWORK
nginx-docker-compose.yml
version: "3.7" services: nginx: image: nginx:latest container_name: nginx hostname: nginx labels: - "traefik.enable=true" - "traefik.http.routers.nginx.entrypoints=websecure" - "traefik.http.routers.nginx.rule=Host(`nginx.$MY_DOMAIN`)" - "traefik.http.routers.nginx.tls.certresolver=lets-encr" - "traefik.http.routers.nginx.tls.domains[0].main=nginx.$MY_DOMAIN" networks: default: external: name: $DEFAULT_NETWORK
運行容器
docker-compose -f traefik-docker-compose.yml up -d docker-compose -f whoami-docker-compose.yml up -d docker-compose -f nginx-docker-compose.yml up -d
DNS 挑戰的全部重點就是獲取通配符!
很公平
因此,對於通配符,這些標籤將加入 traefik compose。
- 與以前一樣使用相同的
lets-encr
證書解析器,它在 traefik.yml 中定義 - 子域(*.example.com)的通配符被設置為要獲取證書的主域
- 裸域(只是簡單的example.com)設置為sans(主題備用名稱)
同樣,您確實需要 * .example.com
和 example.com
在 DNS 控制面板中設置為 A 記錄,指向 traefik 的 IP
traefik-docker-compose.yml
version: "3.7" services: traefik: image: "traefik:v2.1" container_name: "traefik" hostname: "traefik" env_file: - .env ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yml:/traefik.yml:ro" - "./acme.json:/acme.json" labels: - "traefik.enable=true" - "traefik.http.routers.traefik.tls.certresolver=lets-encr" - "traefik.http.routers.traefik.tls.domains[0].main=*.$MY_DOMAIN" - "traefik.http.routers.traefik.tls.domains[0].sans=$MY_DOMAIN" networks: default: external: name: $DEFAULT_NETWORK
現在,如果容器想作為子域進行訪問,則只需要一個具有 url 規則的常規路由器,位於 443 端口入口點,並使用相同的 lets-encr
證書解析器
whoami-docker-compose.yml
version: "3.7" services: whoami: image: "containous/whoami" container_name: "whoami" hostname: "whoami" labels: - "traefik.enable=true" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.rule=Host(`whoami.$MY_DOMAIN`)" - "traefik.http.routers.whoami.tls.certresolver=lets-encr" networks: default: external: name: $DEFAULT_NETWORK
nginx-docker-compose.yml
version: "3.7" services: nginx: image: nginx:latest container_name: nginx hostname: nginx labels: - "traefik.enable=true" - "traefik.http.routers.nginx.entrypoints=websecure" - "traefik.http.routers.nginx.rule=Host(`nginx.$MY_DOMAIN`)" - "traefik.http.routers.nginx.tls.certresolver=lets-encr" networks: default: external: name: $DEFAULT_NETWORK
這是apache,但這次運行在裸域 example.com
上
apache-docker-compose.yml
version: "3.7" services: apache: image: httpd:latest container_name: apache hostname: apache labels: - "traefik.enable=true" - "traefik.http.routers.apache.entrypoints=websecure" - "traefik.http.routers.apache.rule=Host(`$MY_DOMAIN`)" - "traefik.http.routers.apache.tls.certresolver=lets-encr" networks: default: external: name: $DEFAULT_NETWORK
轉發 HTTP 流量到 HTTPS
http 停止使用 https 設置,最好將 http(80) 重定向到 https(443)。
Traefik 有專門的中間件 — redirectscheme。
當 traefik.yml
本身設置為文件提供程序時,可以在動態部分的 traefik.yml
中的多個位置聲明此重定向。
或在任何正在運行的容器中使用標籤,此示例在 traefik compose 中進行操作。
使用 traefik 中的標籤添加新路由和重定向方案
- "traefik.enable=true"
在這個 traefik 容器上啟用 traefik,不是說這裡需要到服務的典型路由,而是說沒有它其他標籤就不能工作
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
創建一個名為 redirect-to-https
的新中間件,輸入 “redirectscheme” 併為其分配方案 https
。
- "traefik.http.routers.redirect-https.rule=hostregexp(`{host:.+}`)"
創建一個名為 redirect-https
的新路由,並使用一個正則表達式規則來捕獲所有傳入請求
- "traefik.http.routers.redirect-https.entrypoints=web"
聲明此路由器在哪個入口點上偵聽 - Web(端口80)
- "traefik.http.routers.redirect-https.middlewares=redirect-to-https"
將新創建的 redirectscheme 中間件分配給此新創建的路由。
traefik-docker-compose.yml
version: "3.7" services: traefik: image: "traefik:v2.1" container_name: "traefik" hostname: "traefik" env_file: - .env ports: - "80:80" - "443:443" - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./traefik.yml:/traefik.yml:ro" - "./acme.json:/acme.json" labels: - "traefik.enable=true" ## DNS CHALLENGE - "traefik.http.routers.traefik.tls.certresolver=lets-encr" - "traefik.http.routers.traefik.tls.domains[0].main=*.$MY_DOMAIN" - "traefik.http.routers.traefik.tls.domains[0].sans=$MY_DOMAIN" ## HTTP REDIRECT - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - "traefik.http.routers.redirect-https.rule=hostregexp(`{host:.+}`)" - "traefik.http.routers.redirect-https.entrypoints=web" - "traefik.http.routers.redirect-https.middlewares=redirect-to-https" networks: default: external: name: $DEFAULT_NETWORK