Traefik 是一套用 Go 寫的雲原生反向代理(GitHub 65,350 星、MIT 授權、最新 v3.7.16)。它跟 Nginx 最大的差別是「路由寫在容器標籤上」:你改 docker-compose 加幾行 labels,Traefik 監聽 Docker 事件就自動生成路由並申請 HTTPS 憑證,全程不用重啟、不用 reload。
如果你的 VPS 上已經跑了五六個容器——密碼管理器、監控、書籤、記帳、AI 聊天介面——那你遲早會遇到同一個問題:每個服務一個連接埠,記不住、防火牆開一堆、憑證還要自己續。Traefik 就是專門解決這件事的,而且它的解法比多數人想的更徹底。
這篇從概念、可複製的設定、middleware 實戰,一路講到 8 個真實踩雷與「Traefik 還是 Caddy」的選擇題。
一表看懂:Traefik 是什麼、跟別人有什麼不同
| 項目 | 內容 |
|---|---|
| 定位 | Cloud Native Application Proxy(雲原生應用代理) |
| GitHub | traefik/traefik,65,350 星、6,267 forks、961 open issues(2026-10-24 API 查詢) |
| 授權 | MIT |
| 語言 | Go |
| 首版 | 2015-09-13 |
| 最新穩定版 | v3.7.16(2026-10-20 發布,同時維護 v2.11.60) |
| 官方文件 | https://doc.traefik.io/traefik/ |
| 設定來源 | Docker、Swarm、Kubernetes(Ingress/CRD/Gateway API)、Nomad、Consul、etcd、Redis、ZooKeeper、File、HTTP |
| 憑證 | 內建 ACME(Let’s Encrypt/ZeroSSL、支援 EAB 與 DNS-01 萬用字元) |
| 商業版 | Traefik Hub(API 管理)、Traefik Enterprise;開源版本身功能完整 |
它跟 Nginx、Caddy 的根本差異
Nginx 的世界是「設定檔 + reload」:你寫 server {} block,改完 nginx -s reload。Traefik 的世界是「服務自己宣告自己」:容器在標籤裡寫「我是 app.example.com,走 3000 埠」,Traefik 從 Docker API 看到這個容器上線,路由就長出來了。
| 面向 | Traefik | Nginx | Caddy |
|---|---|---|---|
| 靜態網站 | 可以,但不是強項 | 極強 | 極強 |
| 容器自動發現 | ✅ 原生(監聽 Docker 事件) | ❌ 要自己寫 upstream 或改設定 reload | ⚠️ 有 docker-proxy 外掛,非內建 |
| 自動 HTTPS | ✅ 內建 ACME | ❌ 要配 certbot | ✅ 內建(更省事) |
| 設定心智負擔 | 高(概念多:entryPoint/router/service/middleware) | 中 | 低(Caddyfile 五行搞定) |
| 動態設定重載 | ✅ 不用重啟 | ⚠️ reload | ⚠️ 自動 reload 設定檔 |
| 進階流量控制 | ✅ middleware 鏈、circuit breaker、retry、rate limit | ⚠️ 需模組或商業版 | ⚠️ 較少 |
| 適合場景 | 多容器、多網域、需要集中治理 | 傳統單體、極致效能 | 單機自架、想少寫設定 |
一句話:服務數量少、設定想簡單 → Caddy;服務十幾個、要集中管路由與憑證 → Traefik。(Caddy 的完整教學可看文末延伸閱讀。)
核心概念:四個名詞擋住 90% 新手
Traefik 的學習曲線不是語法難,是概念不熟。先把這組關係背起來,後面全部豁然開朗:
| 名詞 | 角色 | 類比 |
|---|---|---|
| EntryPoint | 對外開的門(:80、:443) | 大樓的門 |
| Router | 判斷「這個請求該去哪」的規則(Host(...)、PathPrefix(...)) | 門口的接待員 |
| Service | 真正把流量送到哪個後端與連接埠 | 接待員手上那份名單 |
| Middleware | 在 Router 與 Service 之間插入的處理(轉址、驗證、壓縮、限流) | 走道上的關卡 |
| Provider | Router/Service 這些設定的來源(Docker、File、K8s…) | 名單是誰給的 |
而且 Traefik 的設定分成兩層,這是新手最容易混淆的地方:
| 層級 | 內容 | 需要重啟嗎 |
|---|---|---|
| 靜態設定(Static) | entryPoints、providers、certificatesResolvers、api、log、metrics | 要(因為是啟動參數) |
| 動態設定(Dynamic) | routers、services、middlewares | 不用,Provider 一更新就生效 |
所以:憑證解析器、入口點放在靜態設定(traefik.yml 或 CLI 參數);路由與 middleware 放在動態設定(Docker labels 或 dynamic file)。
實戰一:最小可用的 docker-compose
以下直接在 VPS 上跑得起來。先建目錄與兩個檔案:
mkdir -p ~/traefik && cd ~/traefik
touch acme.json && chmod 600 acme.json
# ~/traefik/traefik.yml(靜態設定)
api:
dashboard: true # 啟用 dashboard,但「不要」開 insecure
insecure: false
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
docker:
exposedByDefault: false # 只有標了 traefik.enable=true 的容器才曝露
network: proxy # 預設用這個 network 連後端
file:
directory: /etc/traefik/dynamic
watch: true
certificatesResolvers:
le:
acme:
email: your-email@example.com
storage: /acme.json
httpChallenge:
entryPoint: web
# ~/traefik/docker-compose.yml
services:
traefik:
image: traefik:v3.7
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./dynamic:/etc/traefik/dynamic:ro
- ./acme.json:/acme.json
networks:
- proxy
labels:
- "traefik.enable=true"
# Dashboard router(走 api@internal 服務)
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=le"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=dash-auth@docker"
# Dashboard 的基本驗證(htpasswd 產生,compose 內 $ 要寫成 $$)
- "traefik.http.middlewares.dash-auth.basicauth.users=admin:$$apr1$$xxxxxxxx$$yyyyyyyyyyyyyyyyyyyyyyy"
networks:
proxy:
name: proxy
啟動:docker compose up -d,看 log 確認 Configuration loaded 且沒有 ACME 錯誤。
幾個關鍵決定,值得特別說明:
exposedByDefault: false— 官方預設是true(所有容器自動曝露,規則用Host({{ normalize .Name }}))。自架環境強烈建議關掉,不然你哪天開了一個內網測試容器,它可能就默默對外了。- Docker socket 掛
:ro— 唯讀能減少風險,但這不等於安全邊界(有 socket 就能控制 Docker,等同 root)。講究的話請加 socket-proxy(見第八節)。 acme.json用單檔 bind mount 而不是整個目錄 — 這樣權限好控。
實戰二:用 labels 曝露一個服務
假設你已經有 Vaultwarden 或 Karakeep 在跑,把它的 compose 改成下面這樣(重點是 networks 與 labels):
services:
app:
image: some/app:latest
restart: unless-stopped
networks:
- proxy
labels:
- "traefik.enable=true"
# 1) Router:哪個網域、哪個入口點
- "traefik.http.routers.app.rule=Host(`app.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=le"
# 2) Middleware:HTTP 轉 HTTPS、加上安全標頭
- "traefik.http.routers.app.middlewares=redirect-https@file,sec-headers@file"
# 3) Service:後端容器內部連接埠(容器 expose 多埠時必寫)
- "traefik.http.services.app.loadbalancer.server.port=3000"
# 4) 若容器同時接多個 network,指定 Traefik 走哪一個
- "traefik.docker.network=proxy"
networks:
proxy:
external: true
把它拆成四塊記就不會亂:Router(規則/入口點/TLS/middleware)→ Service(後端埠)→ 網路(走哪張網)→ 開關(traefik.enable)。
驗證方式:開 dashboard 的 HTTP Routers 區,看得到這個 router 就代表設定被吃進去了。看不到的話通常是三件事:沒標 traefik.enable=true、容器不在 proxy network、或 label 拼錯(Traefik 不會報錯,只會忽略)。
實戰三:自動 HTTPS 三種挑戰怎麼選
Traefik 的 ACME 靠 Lego 實作,支援的 DNS provider 清單也在那邊。三種驗證方式差異很大:
| 挑戰 | 需求 | 萬用字元 | 適用 |
|---|---|---|---|
HTTP-01(httpChallenge) | 80 埠必須對外可達 Let’s Encrypt | ❌ | 單機、80 埠沒被佔用 |
TLS-ALPN-01(tlsChallenge) | 443 埠必須對外可達 | ❌ | 80 埠被 ISP 封鎖(例如家用線路) |
DNS-01(dnsChallenge) | 需要 DNS provider API token | ✅ | 要 *.example.com、或完全不想開 80 埠 |
萬用字元憑證只能走 DNS-01,這是 ACME 協定層的限制。DNS-01 的設定長這樣:
certificatesResolvers:
le:
acme:
email: your-email@example.com
storage: /acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
對應的環境變數依 provider 而定(Cloudflare 是 CF_DNS_API_TOKEN),要一併傳給 Traefik 容器。若你的內網擋外部 DNS 查詢,可加 propagation.delayBeforeChecks 延後 TXT 檢查。
其他幾個憑證相關的預設值,知道一下比較不會被嚇到:
| 參數 | 預設 | 說明 |
|---|---|---|
acme.keyType | RSA4096 | 想用小一點的憑證可改 EC256 |
acme.certificatesDuration | 2160(小時=90 天) | 只用來推算續期時間 |
| 續期時機 | 到期前 30 天 | 自動追蹤到期日 |
acme.storage | acme.json | 必填 |
官方也提醒一件事:Traefik 不會檢查憑證是否還在使用,已不用的網域仍可能被續期。所以網域下線後記得清 acme.json,不然會累積。
實戰四:Middleware 實戰四件套
Middleware 建議集中寫在 dynamic file(dynamic/middlewares.yml),這樣多個容器可以共用,不必在每個 compose 重複貼。
# ~/traefik/dynamic/middlewares.yml
http:
middlewares:
# 1) HTTP → HTTPS 永久轉址
redirect-https:
redirectScheme:
scheme: https
permanent: true
# 2) 安全標頭(HSTS、nosniff、frame deny)
sec-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
contentTypeNosniff: true
frameDeny: true
browserXssFilter: true
# 3) gzip/zstd 壓縮
gzip:
compress: true
# 4) 限流:平均 100 req/s、突發 50
rate-limit:
rateLimit:
average: 100
burst: 50
套用到 router 時用逗號串接,順序就是執行順序(先轉址、再壓縮、最後限流):
- "traefik.http.routers.app.middlewares=redirect-https@file,gzip@file,rate-limit@file"
這裡有個 Traefik 特有語法要注意:middleware 與 service 的引用都要帶 provider 後綴——@file、@docker、@internal。少了 @file 就會出現「middleware not found」,是新手最高頻的錯誤之一。
RedirectScheme 的一個隱藏陷阱
官方文件特別註明:如果 Traefik 前面還有另一層反向代理(例如 Cloudflare、或另一台 Nginx),那個上一跳必須被設為 trusted。否則 Traefik 會清掉它帶來的 X-Forwarded-* 標頭,而 redirectScheme 正是靠這些標頭判斷原始 scheme——結果就是轉址失效或無限迴圈。解法是在 entryPoint 設定 forwardedHeaders.trustedIPs。
實戰五:把 dashboard 安全地開出來
官方文件講得很清楚,dashboard 與 API 必須同時保護,做法是「建一個 router 指向 api@internal,掛上驗證 middleware」。規則必須涵蓋 /api 與 /dashboard 兩個前綴,最簡單的寫法是直接用 Host 規則:
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=dash-auth@docker"
想更嚴格可以改成 Host(...) && (PathPrefix(\/api`) || PathPrefix(`/dashboard`)),或再加一層 ipAllowList` 限定來源 IP。
千萬不要為了方便把 api.insecure: true 開在生產環境——那等於把 dashboard 與 API 無驗證掛在 8080 埠上,官方文件直接用粗體警告這件事。
密碼用 htpasswd -nbB admin '你的密碼' 產生,貼進 label 時 compose 內的 $ 必須寫成 $$(compose 會做變數展開,這是第二高頻的踩雷)。
8 個實務踩雷(按踩到機率排序)
| # | 症狀 | 原因 | 解法 |
|---|---|---|---|
| 1 | 502 Bad Gateway | 容器不在 Traefik 所在 network,或連錯埠 | 讓容器與 Traefik 同接 proxy network;必要時標 traefik.docker.network=proxy |
| 2 | 502 且埠明顯錯 | 容器 expose 多個埠,Traefik 猜錯 | 明確寫 traefik.http.services.<name>.loadbalancer.server.port=3000 |
| 3 | Router 完全沒出現 | 沒標 traefik.enable=true(在 exposedByDefault: false 下) | 補 label;或檢查 label 前綴有沒有打錯(打錯不會報錯,只會靜默忽略) |
| 4 | middleware "xxx" does not exist | 引用時漏了 @file / @docker 後綴 | 一律寫成 xxx@file |
| 5 | ACME 憑證要不到 | acme.json 權限太開,Traefik 拒絕載入 | chmod 600 acme.json(經典錯誤訊息:permissions ... for /acme.json are too open) |
| 6 | HTTP 沒自動轉 HTTPS | 忘了掛 redirectScheme,或前面還有代理導致 X-Forwarded-* 被清 | 加 middleware;多層代理時設 forwardedHeaders.trustedIPs |
| 7 | 想簽 *.example.com 一直失敗 | 用了 HTTP-01/TLS-ALPN-01 | 萬用字元只能走 DNS-01 |
| 8 | 連線數一多就掛、日誌爆量 | Docker socket 直通 + 沒有限流/沒開 access log 輪替 | 改 socket-proxy、加 rateLimit、設定 accessLog 輪替 |
第 5 點值得多說一句:這是從 v2 時代就存在的長期行為(社群 issue 從 2017 年一路到 2020 年都有人在問),它就是設計上的故意——避免憑證私鑰被同機其他使用者讀走。所以 touch acme.json && chmod 600 是每個 Traefik 教學都該寫、卻常常漏寫的一行。
進階:Docker socket 的安全替代方案
把 /var/run/docker.sock 直接掛進容器,等於給 Traefik(以及任何能打進 Traefik 漏洞的人)root 等級的宿主控制權。標準做法是中間夾一層 socket proxy,只開放唯讀端點:
services:
socket-proxy:
image: tecnativa/docker-socket-proxy
restart: unless-stopped
environment:
CONTAINERS: 1 # 只開容器讀取
SERVICES: 1
TASKS: 1
NETWORKS: 1
POST: 0 # 關掉所有寫入
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
traefik:
# ...
environment:
- DOCKER_HOST=tcp://socket-proxy:2375
# 移除原本的 docker.sock 掛載
代價是多一個容器、多一個故障點,但這是把「Traefik 被攻破」的影響範圍從「整台機器」縮小到「只看得到容器清單」的關鍵一步。
該用 Traefik 嗎?三種情境的決策表
| 你的狀況 | 建議 | 理由 |
|---|---|---|
| 一台 VPS、3 個以下服務、想快點上線 | Caddy | Caddyfile 五行收工,概念少一半 |
| 一台 VPS、5 個以上容器、常常加新服務 | Traefik | 加服務只改該服務的 compose,不用動代理設定 |
| 多網域 + 多子網域 + 要萬用字元憑證 | Traefik | DNS-01 與 certificateResolver 集中管理 |
| 未來要搬上 Kubernetes | Traefik | 同一套概念直接對應 Ingress/CRD |
| 只跑靜態網站、追求極致靜態效能 | Nginx 或 Caddy | Traefik 不是靜態檔案伺服器的最佳解 |
| 團隊沒人想學新概念 | Caddy | 學習成本是 Traefik 最大的隱形成本 |
老實說,Traefik 的設定負擔比你預期的高。它的抽象層很漂亮,但出事時的除錯資訊不算友善——label 拼錯不會報錯、路由優先級要自己推、middleware 順序有意義。如果你只是想讓一個部落格有 HTTPS,用 Caddy 三分鐘就好,不必為了「雲原生」三個字付學費。
但如果你已經有十個容器在跑、每次新增服務都要手動加 Nginx upstream 再 reload,那 Traefik 省下的時間會在第三次新增服務時就回本。
查證說明
- 星數/forks/issue 數、最新版本:2026-10-24 以 GitHub API(
api.github.com/repos/traefik/traefik、/releases)查詢,非網頁快取值。官方文件頁面顯示 65.4k 星、6.3k forks,與 API 一致。 - 設定語法、預設值、ACME 選項、dashboard 保護方式:全部取自官方文件(quick-start、ACME、Docker provider、API & Dashboard、RedirectScheme、BasicAuth 各頁)。
- 本文未實測的部分:沒有在本次寫作環境實際起一套 Traefik 跑完 ACME 簽發流程(需要真實網域與 80/443 對外)。所有 YAML 皆逐項對照官方文件語法,但請以你自己的環境實跑結果為準。第 5 點的
acme.json權限行為引用自專案長期存在的社群 issue(如 #6972),不同版本訊息措辭可能略有差異。
延伸閱讀
- Caddy 完整教學 2026:75K 星自動 HTTPS 網頁伺服器 — 如果你的服務數量不多,這條路更省事。
- Nginx 反向代理完整教學 — 想對照「傳統設定檔派」怎麼做,從這篇看起。
- CrowdSec 完整教學 2026 — Traefik 最常見的資安搭檔,把反向代理的 access log 直接餵給群眾情報防火牆。
- Coolify 完整教學 2026:62K 星開源自架版 Vercel/Heroku — 用 Coolify 部署時,它內建就幫你處理反向代理;但想自己控路由就回到 Traefik。
- Uptime Kuma 完整教學 2026:91K 星自架監控神器 — 服務上線後,下一步就是監控它活著。
- Vaultwarden 完整教學 2026:自架 Bitwarden 相容密碼管理器 — Traefik 最常見的搭配對象之一。
- OpenAI 前沿模型訓練全面斷網:DNS 隧道越獄與「離線世界」全解析 — 順帶一提,連 AI 實驗室都在頭痛「邊界要怎麼守」,你的反向代理就是自家邊界的第一層。
資料來源
- Traefik 官方文件 — Docker Quick Start:https://doc.traefik.io/traefik/getting-started/quick-start/
- Traefik 官方文件 — Docker Provider:https://doc.traefik.io/traefik/reference/install-configuration/providers/docker/
- Traefik 官方文件 — ACME Certificate Resolver:https://doc.traefik.io/traefik/https/acme/
- Traefik 官方文件 — API & Dashboard:https://doc.traefik.io/traefik/reference/install-configuration/api-dashboard/
- Traefik 官方文件 — RedirectScheme:https://doc.traefik.io/traefik/reference/routing-configuration/http/middlewares/redirectscheme/
- Traefik 官方文件 — BasicAuth:https://doc.traefik.io/traefik/reference/routing-configuration/http/middlewares/basicauth/
- GitHub API — https://api.github.com/repos/traefik/traefik(查證於 2026-10-24)
- Lego(ACME 實作與 DNS provider 清單):https://go-acme.github.io/lego/
