Traefik 常用 Middleware 介紹與應用
Middlewares 是 Traefik 用來調整請求 (Request) 和回應 (Response) 的強大工具。它們像是一個個串連起來的管道,請求通過時會被依照順序處理。
本章將介紹幾個最實用的 Middleware。
身份驗證 (BasicAuth)
BasicAuth 是最快為服務加上密碼保護的方法。我們可以用它來保護 Traefik Dashboard 或是尚未準備好公開的測試站。
產生密碼
首先,你需要產生一組經過加密的帳號密碼。你可以使用 htpasswd 工具 (Apache utils) 或線上工具。
# user: test, password: testpassword
echo $(htpasswd -nb test testpassword)
# 輸出: test:$apr1$H6...
將 $apr1$... 中的 $ 替換成 $$ (因為 YAML 中 $ 是變數符號,需要轉義),或者直接用單引號包起來。
定義與應用 Middleware
labels:
# 定義一個名為 "auth" 的 Middleware
- 'traefik.http.middlewares.auth.basicauth.users=test:$apr1$H6...'
# 將 "auth" Middleware 套用到 Router "whoami"
- 'traefik.http.routers.whoami.middlewares=auth'
現在,存取 whoami 服務時,瀏覽器就會跳出帳號密碼輸入框了。
路徑重寫 (StripPrefix)
有時候你想把服務掛在子路徑下,例如 /api/v1,但後端服務本身預期的是根路徑 /。這時就需要 StripPrefix。
labels:
# 定義路由規則:匹配 /api 開頭的請求
- 'traefik.http.routers.backend.rule=PathPrefix(`/api`)'
# 定義 Middleware:去除 /api 前綴
- 'traefik.http.middlewares.strip-api.stripprefix.prefixes=/api'
# 套用 Middleware
- 'traefik.http.routers.backend.middlewares=strip-api'
請求流程:
- 使用者請求
http://example.com/api/users。 - Traefik 匹配到
/api。 - StripPrefix 去除
/api,剩下/users。 - 後端服務收到
GET /users。
流量限制 (RateLimit)
保護你的服務免受 DDoS 攻擊或濫用。
預設情況下,Traefik 是根據 客戶端來源 IP (Client IP) 來限制流量的。每個 IP 擁有獨立的配額。
forwardedHeaders 信任代理伺服器,Traefik 才能讀取 X-Forwarded-For 取得真實的客戶端 IP。labels:
# 定義 rate limit middleware
# average: 每秒平均允許 100 個請求 (Refill Rate)
- 'traefik.http.middlewares.ratelimit.ratelimit.average=100'
# burst: 令牌桶 (Bucket) 大小。決定了瞬間最大允許的請求數量
# 這裡設為 150,表示允許瞬間突發 150 個請求 (消耗完 150 個 token 後,需等待回補)
- 'traefik.http.middlewares.ratelimit.ratelimit.burst=150'
# 套用
- 'traefik.http.routers.whoami.middlewares=ratelimit'
超過限制的請求會收到 429 Too Many Requests。
為什麼需要 Average 和 Burst?
Traefik 使用的是 Token Bucket (令牌桶) 演算法,你可以把它想像成一個水桶:
- Burst (水桶大小):決定了這個桶子最多能裝多少水。這代表了系統能承受的瞬間突發流量。在此範例中,我們設為
150,表示桶子滿的時候,使用者可以瞬間發送 150 個請求而不會被阻擋。 - Average (補水速度):決定了每秒鐘有多少水流進桶子。這代表了長期平均速率。在此範例中,
100表示每秒鐘會補充 100 個額度到桶子裡(直到桶子滿為止)。
如果只設定 Burst 會發生什麼事? 如果只給桶子大小 (Burst),但沒有補水速度 (Average),那桶子裡的水用完就沒了,使用者再也無法發送請求。所以必須有一個速率來持續補充額度。
這個機制的好處是:允許偶爾的突發流量 (因為桶子有庫存),但在長時間下,流量會被限制在 Average 的速率。
壓縮 (Compress)
自動啟用 Gzip 或 Brotli 壓縮回應內容,節省頻寬並加快載入速度。
labels:
# 定義 Compress Middleware (預設設定即可)
- 'traefik.http.middlewares.compress.compress=true'
# 套用
- 'traefik.http.routers.whoami.middlewares=compress'
注意:Middleware 的順序很重要。通常我們會把 Compress 放在 StripPrefix 或 Authentication 之後,因為沒必要壓縮被拒絕的請求。
但在 Traefik 中,Middleware 的執行順序是由它們在 middlewares 列表中的順序決定的嗎?
不完全是。在 Traefik v2/v3,如果透過 Docker Label 定義,並且在 Router 上引用多個 Middleware,例如 middlewares=auth,compress,它們會依照定義好的順序執行。
推薦方式:Chain Middleware。
串聯 (Chain)
如果你有多個 Router 都需要同一組 Middleware (例如:HTTPS Redirect + Auth + RateLimit),重複寫很麻煩。你可以定義一個 Chain。
這個例子比較適合在 File Provider 中定義,但在 Docker 中也可以:
labels:
# 定義 chain
- 'traefik.http.middlewares.secured.chain.middlewares=auth,ratelimit,compress'
# 路由直接引用 chain
- 'traefik.http.routers.whoami.middlewares=secured'
這樣管理起來就整潔多了!
安全性標頭 (Headers)
最後,為了讓網站更安全 (滿足 HSTS, XS-Protection 等),你可以使用 Headers Middleware:
labels:
- 'traefik.http.middlewares.security-headers.headers.sslredirect=true'
- 'traefik.http.middlewares.security-headers.headers.stsSeconds=315360000'
- 'traefik.http.middlewares.security-headers.headers.browserXssFilter=true'
- 'traefik.http.routers.whoami.middlewares=security-headers'
善用這些 Middlewares,你就可以在不修改後端程式碼的情況下,為整個基礎架構加上許多強大的功能。