所有部署指南 部署

如何在 Traefik (v3) 上安裝自訂 SSL 憑證

Traefik 以透過 ACME 自動簽發憑證而聞名。但有時候你需要改用自己的憑證——例如由 GetHTTPS 簽發的憑證、企業/內部 CA 的憑證,或是你在別處管理的萬用字元(wildcard)憑證。本指南會在 Traefik v3 上,明確示範該怎麼做。

首先要理解的關鍵重點是:你無法用 Docker label 來掛載憑證檔案。 Traefik label 控制路由並啟用 TLS,但憑證本身必須由 file provider 以動態設定的形式提供。幾乎每個人第一次都會在這裡踩坑。我們會用正確的方式來做。

如果你還沒有憑證,5 分鐘免費取得一張

何時使用此方法(相較於 Traefik 自動 ACME)

使用自動 ACME(Let’s Encrypt)使用你自己的憑證(本指南)
公開網站,可從網際網路存取內部/內網服務(無公開 DNS)
標準 DV 憑證即可滿足需求你需要特定 CA、萬用字元或 OV/EV 憑證
Traefik 可完成 HTTP/DNS 驗證挑戰實體隔離(air-gapped)或有防火牆阻擋的主機
你想要零憑證管理你已經有一張來自 GetHTTPS 或其他來源的憑證

如果自動 ACME 適合你的情況,使用 Traefik 的 certificatesResolvers 會更簡單。本指南適用於「我已經有 fullchain.pem + privkey.pem,需要讓 Traefik 提供它們」的情境。

先決條件

  • Traefik v3 以 Docker 容器執行(下方設定使用 Docker,但動態設定的部分適用於任何環境)
  • 你的憑證檔案——共兩個:
    • fullchain.pem — 你的憑證 + 中繼信任鏈
    • privkey.pem — 你的私鑰
  • 一個指向該主機的網域(或供內部使用的本機 hosts 檔項目)

Traefik 需要哪些檔案? Traefik 在 certFile 需要完整的信任鏈,在 keyFile 需要私鑰。如果你使用僅含葉憑證(leaf-only)的 cert.pem,用戶端會收到「不完整的信任鏈」錯誤——Traefik 不會為 file-provider 憑證自動附加中繼憑證。請使用 fullchain.pem憑證格式說明 →

Traefik 的設定如何分割

Traefik 有兩種設定,而憑證屬於第二種:

  • 靜態設定(Static configuration)——在啟動時設定(entrypoint、provider)。變更後需要重啟。這部分放在 traefik.yml 或容器的命令列 flag。
  • 動態設定(Dynamic configuration)——無需重啟即可即時重新載入(router、service、TLS 憑證)。這正是 file provider 所讀取的內容。

你的憑證屬於動態設定。這就是為什麼 label 無法承載它——label 由 Docker provider 讀取,但 tls.certificates 是 file-provider 的概念。

步驟 1:放置憑證檔案

把檔案放進你將掛載到容器內的目錄:

mkdir -p ./traefik/certs
cp fullchain.pem ./traefik/certs/
cp privkey.pem   ./traefik/certs/

# 鎖定私鑰權限
chmod 600 ./traefik/certs/privkey.pem
chmod 644 ./traefik/certs/fullchain.pem

步驟 2:撰寫動態設定

建立 ./traefik/dynamic/certs.yml。這裡就是你宣告憑證的地方:

# ./traefik/dynamic/certs.yml  (動態設定 — file provider)
tls:
  certificates:
    - certFile: /certs/fullchain.pem
      keyFile: /certs/privkey.pem

  # Optional: make this cert the default for any host that doesn't
  # match a more specific certificate (e.g. a wildcard or internal CA).
  stores:
    default:
      defaultCertificate:
        certFile: /certs/fullchain.pem
        keyFile: /certs/privkey.pem

這些路徑(/certs/...)是容器內的路徑——我們會在下一步掛載它們。Traefik 會透過 SNI 為每個請求挑選正確的憑證,將憑證的 SAN 與請求的主機名稱比對。當沒有其他憑證符合時,defaultCertificate 就是後備(fallback)。

步驟 3:設定 Traefik(靜態設定 + 掛載)

以下是一份完整的 docker-compose.yml。entrypoint 與 file provider 屬於靜態設定(以命令列 flag 傳入);憑證則從你剛寫好的動態檔案載入。

services:
  traefik:
    image: traefik:v3.3
    container_name: traefik
    restart: unless-stopped
    command:
      # ─── Entrypoints ───────────────────────────────
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      # Redirect all HTTP → HTTPS at the entrypoint level
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
      # ─── Providers ─────────────────────────────────
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      # File provider watches the dynamic config directory
      - "--providers.file.directory=/dynamic"
      - "--providers.file.watch=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik/certs:/certs:ro"
      - "./traefik/dynamic:/dynamic:ro"

  # ─── Example backend service ──────────────────────
  whoami:
    image: traefik/whoami
    container_name: whoami
    labels:
      - "traefik.enable=true"
      # Router: match the host, serve on the HTTPS entrypoint
      - "traefik.http.routers.whoami.rule=Host(`example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      # Enable TLS on this router — certificate comes from the
      # dynamic config, NOT from a label.
      - "traefik.http.routers.whoami.tls=true"

最關鍵的一行是 traefik.http.routers.whoami.tls=true 它告訴 Traefik「以 TLS 提供此 router」。接著 Traefik 會透過 SNI,從 file-provider 的儲存區挑出相符的憑證。並沒有tls.certfile 這樣的 label——router 並不存在這種東西。

步驟 4:啟動並驗證

docker compose up -d
docker compose logs -f traefik

留意 file provider 載入你憑證的訊息。你應該不會看到 TLS 錯誤。然後進行驗證:

瀏覽器檢查

造訪 https://example.com。點擊鎖頭圖示:

  • 簽發者(Issued by)——你的 CA(GetHTTPS 為 Let’s Encrypt,或你的內部 CA)
  • 有效性(Valid)——起始與到期日期
  • 網域(Domain)——與網址相符

命令列檢查

# Confirm Traefik is serving YOUR certificate, not its self-signed default
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

如果你看到 CN=TRAEFIK DEFAULT CERT,表示 Traefik 退回使用其內建的佔位憑證——你的憑證並未載入。請參閱下方的疑難排解段落。

步驟 5(選用):強化 TLS

若要控制協定版本與加密套件,請在動態設定中加入一個 TLS options 區塊,並從 router 引用它。把以下內容加進 certs.yml

tls:
  options:
    modern:
      minVersion: VersionTLS12
      sniStrict: true

然後在 router label 上:

- "traefik.http.routers.whoami.tls.options=modern@file"

@file 後綴告訴 Traefik 這組 option 來自 file provider。這會將你限制在 TLS 1.2 與 1.3,並拒絕沒有相符 SNI 的連線。

HSTS: 等你確信 HTTPS 在各處都能正常運作後,再透過 Traefik 的 headers middleware 加上 Strict-Transport-Security 標頭。HSTS 指南 →

如何續期

Traefik 不會自動續期你自行提供的憑證——這是使用自己憑證的取捨。當你的憑證接近到期時(Let’s Encrypt 為 90 天中的第 60 天):

  1. GetHTTPS(或你的續期工具)取得一張新憑證。
  2. 就地覆寫檔案:
    cp new-fullchain.pem ./traefik/certs/fullchain.pem
    cp new-privkey.pem   ./traefik/certs/privkey.pem
  3. 不需要其他動作。 因為已設定 --providers.file.watch=true,Traefik 會偵測到檔案變更並熱重載憑證——無需重啟、零停機。這是 Traefik 在處理自訂憑證時最棒的特性之一。

完整續期指南 →

疑難排解

Traefik 提供「TRAEFIK DEFAULT CERT」而非我的憑證

原因: Traefik 無法載入你的憑證,因此退回使用其自簽的佔位憑證。幾乎都是路徑或掛載的問題。

解決方法:

# 1. Confirm the files exist INSIDE the container at the expected path
docker compose exec traefik ls -l /certs

# 2. Confirm the dynamic file is mounted and readable
docker compose exec traefik cat /dynamic/certs.yml

# 3. Check logs for the real reason
docker compose logs traefik | grep -i "certificate\|tls\|error"

certs.yml 中的 certFilekeyFile 路徑必須符合容器的路徑(/certs/...),而非你主機上的路徑。

「unable to find certificate for domain」/提供了錯誤的憑證

原因: 沒有任何憑證的 SAN 符合請求的主機名稱,而且也沒有設定 defaultCertificate

解決方法: 要嘛把該主機名稱加進你的憑證,要嘛在 stores.default 區塊(步驟 2)設定一個 defaultCertificate,讓 Traefik 有後備可用。

Router 回傳 404,憑證根本沒被檢查

原因: router 規則不相符,或服務未被公開。在路由相符之前,TLS 都是無關緊要的。

解決方法:

# Verify the router exists and is enabled
docker compose exec traefik wget -qO- http://localhost:8080/api/http/routers 2>/dev/null | grep whoami

確認後端容器上有 traefik.enable=true,且 Host() 規則符合你正在測試的網域。

對 certs.yml 的變更未生效

原因: file provider 未在監看,或你編輯的是靜態設定(需要重啟)。

解決方法: 確認 --providers.file.watch=true 有在靜態設定中。請記住:entrypoint/provider 屬於靜態設定(需要重啟);router 與 tls.certificates 屬於動態設定(會熱重載)。

用戶端出現「x509: certificate signed by unknown authority」

原因: 信任鏈不完整——你在 certFile 使用了僅含葉憑證的 cert.pem,而非 fullchain.pem

解決方法:certFile 指向完整的信任鏈。如果你只有各自獨立的檔案,請將它們串接起來(葉憑證在前,接著是中繼憑證):

cat cert.pem intermediate.pem > fullchain.pem

常見問題

我可以用 Docker label 指定憑證檔案嗎?

不行。 這是第一大誤解。label 設定 traefik.http.routers.<name>.tls=true啟用 TLS,但憑證檔案必須透過 file provider 在動態設定中宣告(tls.certificates)。並沒有任何 router label 能指向 .pem 檔案。

如果我已經有憑證,router 上還需要 tls=true 嗎?

需要。在 tls.certificates 中宣告憑證會讓它可被使用,但每個 router 仍需要 tls=true(或監聽一個已啟用 TLS 的 entrypoint)才能真正以 HTTPS 提供服務。光是定義憑證並不會把 router 切換到 TLS。

我可以混用自動 ACME 與自訂憑證嗎?

可以。Traefik 可以為某些 router 使用 certificatesResolver,同時為其他 router 使用 file-provider 憑證。就單一請求而言,透過 SNI 明確相符的 tls.certificates 對該主機名稱的優先順序高於 ACME。

在 Kubernetes 上憑證放在哪裡?

不是用 file provider——在 Kubernetes 上,你以 TLS Secrets 形式提供憑證,並從 IngressRoute/Ingress 引用它們。本指南中的 file-provider 做法適用於 Docker 與獨立(非 K8s)環境。

Traefik 會自動續期我的自訂憑證嗎?

不會。自動續期僅適用於 Traefik 自己透過 ACME 簽發的憑證。對於你自己的憑證,你需要替換檔案——但多虧了 --providers.file.watch=true,Traefik 會熱重載它們並達到零停機,如上方如何續期段落所述。

這對 ECDSA/ECC 憑證也適用嗎?

適用。Traefik 提供 ECDSA 憑證的方式與 RSA 完全相同——一樣的 certFilekeyFile 設定。GetHTTPS 預設簽發 ECDSA P-256,以獲得更小、更快的交握。

相關文章

部署 2026-05-08
Docker 與反向代理的 SSL 證書配置
為 Docker 容器配置 HTTPS:使用 Nginx 反向代理、Traefik 自動獲取 Let's Encrypt 證書,或手動掛載證書。
快速開始 2026-05-08
如何獲取免費 SSL 證書(分步指南)
5 分鐘從 Let's Encrypt 獲取免費 SSL 證書 — 無需安裝軟體、無需註冊賬號。涵蓋 4 種方法、兩種驗證方式、6 個平臺的安裝教程和故障排除。
部署 2026-05-08
如何在 Nginx 上安裝 SSL 證書
在 Nginx 上安裝 SSL 證書的分步指南。涵蓋檔案上傳、完整 server 塊配置、TLS 最佳實踐、HTTP/2、HSTS、重新導向設定、測試以及 6 個常見錯誤的排查方法。
SSL 與憑證 2026-05-07
SSL 證書格式:PEM、PFX、DER 詳解
理解 PEM、PFX/PKCS#12 和 DER 證書格式。瞭解你的伺服器需要哪種格式,以及如何使用 OpenSSL 在它們之間轉換。
在瀏覽器中取得免費 SSL 憑證
無需安裝,無需帳號。私鑰始終留在你的裝置上。
取得憑證