Docker: HTTPS 路由
如何在 Docker 容器中管理 HTTP 路由和 TLS 加密(HTTPS)
👋 歡迎來到 Stackhero 文件!
Stackhero 提供一個即用型的 Docker cloud CaaS (Containers as a Service) 解決方案,帶來多種好處,包括:
- 只需
docker-compose up即可 輕鬆將 您的容器 部署到生產環境。- 可自訂的域名,並使用 HTTPS 保護(例如,https://api.your-company.com,https://www.your-company.com,https://backoffice.your-company.com)。
- 由 專用的私人 VM 提供的最佳 性能 和強大的 安全性。
- 只需點擊一下即可輕鬆 更新。
節省時間 並 簡化您的生活:只需 5 分鐘 即可嘗試 Stackhero 的 Docker CaaS cloud hosting 解決方案,並將您的容器部署到生產環境!
每個 Stackhero for Docker 實例都包含一個專用且預配置的 Traefik 伺服器,該伺服器管理 HTTP 流量並自動使用 TLS 證書加密。這種簡化的設置使路由變得簡單高效。例如:
- 將
https://www.my-company.com(有或沒有 www 前綴) 的流量發送到您的frontend容器。 - 將
https://www.my-company.com/documentations路由到您的documentations容器。 - 將
https://api.my-project.io直接到您的api容器。
您可以管理無限數量的域名,並自動創建和更新 TLS 證書。最棒的是,您只需三行即可配置所有這些!
Traefik 基本配置
在以下所有配置示例中,您需要將
<XXXXXX>.stackhero-network.com替換為您的 Stackhero for Docker 實例域名。
以下是 docker-compose.yml 文件的基本示例:
services:
test:
image: nginx
labels:
- "traefik.enable=true" # 啟用 Traefik 將流量路由到此容器
- "traefik.http.routers.test.rule=Host(`<XXXXXX>.stackhero-network.com`)" # 定義主機
- "traefik.http.routers.test.tls.certresolver=letsencrypt" # 使用 'letsencrypt' 作為 TLS 證書解析器
在此示例中,名為 test 的容器使用 Nginx 映像運行。關鍵配置在 labels 部分提供。您只需將這些行複製到您的 docker-compose.yml 文件中,並將 <XXXXXX>.stackhero-network.com 替換為您的服務域名。
您可以使用以下命令部署容器:
docker context use <XXXXXX>.stackhero-network.com
docker-compose up
容器啟動後,訪問 https://<XXXXXX>.stackhero-network.com/ 查看 "Welcome to nginx!" 頁面。
Nginx 歡迎頁面
如果您沒有看到 Nginx 歡迎頁面,請檢查 Traefik 儀表板以查看可能的錯誤!
通過此配置,發送到 <XXXXXX>.stackhero-network.com 的 HTTP 請求將被路由到您的 test 容器,並且 Traefik 自動創建和管理 HTTPS 的 TLS 證書。
使用 Traefik 處理自定義域名
在前面的示例中,我們使用了默認的 <XXXXXX>.stackhero-network.com 域名。實際上,您可能會使用自己的公司或項目域名,例如 www.my-company.com 或 api.my-project.io。以下部分說明如何配置自定義域名。
使用 Traefik 配置您的第一個域名
在此示例中,您將配置域名 api.my-project.io。將 my-project.io 替換為您擁有的域名,並將 api 替換為您想要的子域名。
首先,更新您的域名 DNS 設置,使 api.my-project.io 指向您的 <XXXXXX>.stackhero-network.com 域名。
- 登錄到您的域名提供商並訪問您的 DNS 配置。
- 創建一個名為
api的新條目(或您選擇的其他子域名),將其類型設置為CNAME,並將其目標設置為<XXXXXX>.stackhero-network.com。
Cloudflare DNS 介面上的 DNS 配置示例
DNS 配置完成後,您可以通過運行以下命令進行驗證:
host api.my-project.io
您應該會看到類似的回應:
api.my-project.io is an alias for <XXXXXX>.stackhero-network.com
DNS 傳播可能需要最多 24 小時,具體取決於您的提供商。 如果
host命令未返回預期的回應,請稍等片刻再重試。
接下來,使用以下配置更新您的 docker-compose.yml 文件:
services:
api:
image: traefik/whoami
hostname: api
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.my-project.io`)" # 在此添加您的域名
- "traefik.http.services.api.loadbalancer.server.port=<PORT>" # 將 "<PORT>" 替換為您的 API 所監聽的端口
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
不要忘記在 Traefik 標籤
Host中將api.my-project.io替換為您的實際域名。
使用以下命令部署您的容器:
docker-compose up -d
然後訪問 https://api.my-project.io。您應該會看到一個顯示您的容器主機名 api 的文本頁面。
證明 Traefik 正在為我們的新域名處理 HTTP 流量並進行 TLS 加密
在首次創建容器時,TLS 證書可能需要幾秒鐘生成。 如果遇到 TLS 錯誤,請稍等幾秒鐘並刷新頁面,以便證書有時間生成。
恭喜,您現在已配置了您的第一個自定義域名!
如何使用 Traefik 將 "www" 子域名重定向到您的根域名
在定義網站 URL(如 my-company.com)時,最好同時設置一個 "www" 子域名。這確保通過 www.my-company.com 連接的用戶被重定向到您的主站點,並有助於避免重複內容問題。
在下面的示例中,my-company.com 和 www.my-company.com 都被處理。訪問 www.my-company.com 的用戶將被重定向到 my-company.com:
services:
frontend:
image: traefik/whoami
hostname: frontend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`my-company.com`) || Host(`www.my-company.com`)" # 在此添加兩個域名
- "traefik.http.services.frontend.loadbalancer.server.port=<PORT>" # 將 "<PORT>" 替換為您的前端所監聽的端口
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
# 將 'www.my-company.com' 重定向到 'my-company.com':
- 'traefik.http.routers.frontend.middlewares=redirect-www'
- "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.my-company.com/(.*)"
- "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://my-company.com/$${1}"
- "traefik.http.middlewares.redirect-www.redirectregex.permanent=true"
使用 Traefik 將路徑路由到特定容器
假設您有一個專門用於文檔網站的容器。您可能希望將 https://my-company.com/docs 路由到此容器,同時將其他請求(如 https://my-company.com/)發送到您的前端容器。下面的示例顯示了如何完成此操作:
services:
documentations:
image: traefik/whoami
hostname: documentations
labels:
- "traefik.enable=true"
- "traefik.http.routers.documentations.rule=Host(`my-company.com`) && PathPrefix(`/docs`)" # 在此定義路徑前綴
- "traefik.http.services.documentations.loadbalancer.server.port=<PORT>" # 將 "<PORT>" 替換為您的文檔容器所監聽的端口
- "traefik.http.routers.documentations.tls.certresolver=letsencrypt"
frontend:
image: traefik/whoami
hostname: frontend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`my-company.com`) || Host(`www.my-company.com`)"
- "traefik.http.services.frontend.loadbalancer.server.port=<PORT>" # 將 "<PORT>" 替換為您的前端所監聽的端口
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
# 將 'www.my-company.com' 重定向到 'my-company.com':
- 'traefik.http.routers.frontend.middlewares=redirect-www'
- "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.my-company.com/(.*)"
- "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://my-company.com/$${1}"
- "traefik.http.middlewares.redirect-www.redirectregex.permanent=true"
現在,訪問 https://my-company.com/docs(或任何子路徑,如 https://my-company.com/docs/something)將顯示來自 documentations 容器的內容。其他路徑,例如 https://my-company.com/help,將由 frontend 容器提供服務。
在 Traefik 中定義自定義容器端口
默認情況下,Traefik 連接到容器的第一個暴露端口。在某些情況下,您可能需要指定特定端口。下面的示例演示如何定義自定義端口:
services:
frontend:
image: traefik/whoami
hostname: frontend
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`my-company.com`)"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
# 將 'https://my-company.com' 的流量路由到 'frontend' 容器的 80 端口
- "traefik.http.services.frontend.loadbalancer.server.port=80"
Traefik 和 Docker Compose 命名的良好實踐
在您的 docker-compose.yml 文件中定義容器時,某些字段對於更好的一致性和管理便利性非常重要。考慮使用以下推薦配置:
services:
<CONTAINER_NAME>:
image: traefik/whoami
hostname: <CONTAINER_NAME>
container_name: <CONTAINER_NAME>
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.<CONTAINER_NAME>.rule=Host(`my-company.com`)"
- "traefik.http.routers.<CONTAINER_NAME>.tls.certresolver=letsencrypt"
只需將 <CONTAINER_NAME> 替換為您想要的容器名稱,例如 frontend。
Let's Encrypt 錯誤 "Domain name contains an invalid character"
在創建子域名時,Let's Encrypt 遵循 RFC 952 和 1123,這些規範僅允許字符集 [a-zA-Z0-9-] 中的字符。
雖然在 DNS 記錄名稱中允許使用下劃線 ('_'),但在主機名中不被接受。因此,Let's Encrypt 拒絕像 "my_subdomain.example.com" 這樣的子域名,並顯示錯誤 "Domain name contains an invalid character"。
要解決此問題,只需從您的子域名中刪除所有下劃線。