Appearance
Caddy 靜態檔案伺服器
使用 Caddy 取代 Nginx 作為 Kubernetes 上的靜態檔案伺服器,提供目錄瀏覽、分層快取策略與內建 Prometheus metrics。
概述
Caddy 是一款以簡潔設定與自動 HTTPS 聞名的現代 Web 伺服器。在本場景中,Caddy 被用來取代 Nginx 作為靜態檔案伺服器,部署在 Kubernetes 叢集中,提供目錄瀏覽(autoindex)與檔案下載功能。
相較於 Nginx,Caddy 的 Caddyfile 語法更簡潔直觀,且內建 Prometheus metrics 支援,無需額外安裝模組。搭配 zstd 與 gzip 壓縮,能有效降低傳輸頻寬。映像採用 caddy:2.10-alpine,體積輕巧。
核心內容
Caddyfile 設定架構
Caddyfile 分為兩個區塊:全域設定(Global Options)與站台設定。
全域設定: 啟用 Admin API(監聽 0.0.0.0:2019)並開啟內建 Prometheus metrics(含 per-host 指標),讓 Prometheus Exporter 部署模式 可直接抓取 Caddy 自身的運行指標,無需額外部署 Exporter。
站台設定(:80): 以 /srv/files 為檔案根目錄,啟用 zstd 與 gzip 壓縮(Caddy 依據客戶端的 Accept-Encoding 自動選擇最佳壓縮演算法)。
分層快取策略
Caddy 針對不同類型的資源設定了四層快取策略,透過 handle 指令與路徑匹配實現:
目錄瀏覽路徑(30 秒): 僅特定路徑(/bj6-updater、/public-updater、/resource-viewer/mrp-report/wiwynn)開放 file_server browse 目錄瀏覽功能,快取時間極短以確保使用者能即時看到更新。
大型下載檔案(30 分鐘): 匹配 .zip、.tar、.gz、.exe、.AppImage、.deb 等壓縮檔與安裝包,設定較長的快取時間以減少重複傳輸。
前端動態資源(30 秒): 匹配 .html、.css、.js、.json、.wasm 等前端資源,搭配 must-revalidate 確保客戶端總是驗證資源是否已更新。
其他檔案(5 分鐘): 不屬於以上任何類別的檔案,給予中等快取時間。
所有快取策略均使用 Vary: Accept-Encoding header,確保壓縮與非壓縮版本的快取不會互相干擾。
目錄瀏覽安全性
值得注意的是,目錄瀏覽功能僅限於三個白名單路徑,其餘路徑雖然可以直接下載已知檔名的檔案,但不會列出目錄內容。這是一個重要的安全考量——避免意外暴露不應公開的檔案清單。
Kubernetes 部署細節
Caddy 容器以 sidecar 或獨立 Pod 形式部署,掛載兩個 Volume:
檔案目錄: 來自名為 sftpgo-volume 的 Volume(subPath: upload),以 readOnly 模式掛載至 /srv/files。這表示 Caddy 與 SFTPGo 共享同一份檔案儲存——使用者透過 SFTP 上傳的檔案,可立即透過 Caddy 的 HTTP 介面瀏覽與下載。
設定檔: Caddyfile 透過 ConfigMap 以 subPath 方式掛載至 /etc/caddy/Caddyfile。
容器設定 TZ=Asia/Taipei 確保日誌時間戳為台灣時區,資源請求為 CPU 150m / Memory 300Mi。
關鍵要點
- Caddy 以簡潔的 Caddyfile 取代 Nginx 複雜的設定語法,降低維護門檻
- 內建 Prometheus metrics 支援,省去額外部署 Exporter 的工作
- 四層快取策略針對不同資源類型最佳化,兼顧即時性與效能
- 目錄瀏覽採白名單制,僅特定路徑開放,兼顧易用性與安全性
- 與 SFTPGo 共享 Volume,形成「SFTP 上傳 → HTTP 下載」的完整檔案分發管線
實際應用
此架構適合企業內部的檔案分發場景:開發團隊透過 SFTP 上傳建置產物(build artifacts)、更新檔、報表等,內網使用者則透過瀏覽器直接下載。Caddy 的快取策略確保頻繁更新的前端資源與較少變動的安裝包各自有合適的快取行為。
部署設定參考
以下為實際部署時使用的完整設定,供日後查詢與複製使用。
環境參數
| 項目 | 值 |
|---|---|
| Container 名稱 | caddy-server |
| Image | caddy:2.10-alpine |
| Image Pull Policy | Always |
| 時區 | Asia/Taipei |
| 對外 Port | 80 |
| Memory Request | 300Mi |
| CPU Request | 150m |
完整 Caddyfile
caddyfile
{
admin 0.0.0.0:2019
servers {
metrics {
per_host
}
}
}
:80 {
root * /srv/files
encode zstd gzip
# --- 目錄瀏覽(autoindex):短快取,30s 內可看到更新 ---
@browsePaths {
path /bj6-updater* /public-updater* /resource-viewer/mrp-report/wiwynn*
}
handle @browsePaths {
header {
Cache-Control "public, max-age=30, must-revalidate"
Vary "Accept-Encoding"
}
file_server browse
}
# --- 大型下載檔案:較長快取 ---
handle /*.(zip|tar|gz|tgz|bz2|xz|7z|rar|exe|AppImage|deb|rpm) {
header {
Cache-Control "public, max-age=1800"
Vary "Accept-Encoding"
}
file_server
}
# --- 前端動態資源:短快取 + revalidate ---
handle /*.(html|css|js|json|wasm) {
header {
Cache-Control "public, max-age=30, must-revalidate"
Vary "Accept-Encoding"
}
file_server
}
# --- 其他檔案:中等快取 ---
handle {
header {
Cache-Control "public, max-age=300, must-revalidate"
Vary "Accept-Encoding"
}
file_server
}
}Kubernetes YAML(Container 片段)
yaml
- name: caddy-server
image: caddy:2.10-alpine
imagePullPolicy: Always
env:
- name: TZ
value: Asia/Taipei
ports:
- containerPort: 80
volumeMounts:
- mountPath: /srv/files
name: sftpgo-volume
subPath: upload
readOnly: true
- name: caddy-config-volume
mountPath: /etc/caddy/Caddyfile
subPath: Caddyfile
resources:
requests:
memory: "300Mi"
cpu: "150m"Volume 掛載摘要
| 掛載路徑 | Volume 名稱 | 說明 |
|---|---|---|
/srv/files | sftpgo-volume(subPath: upload,readOnly) | 檔案目錄 |
/etc/caddy/Caddyfile | caddy-config-volume(subPath: Caddyfile) | 設定檔覆蓋 |
相關概念
- Prometheus Exporter 部署模式 — Caddy 內建 metrics 端點,可直接被 Prometheus 抓取
- Squid Proxy(Kubernetes 部署) — 同樣部署在
ingress-basicnamespace 的網路基礎設施 - Samba + Nginx 檔案分享服務(Kubernetes 部署) — 另一種 Web 目錄瀏覽方案,以 Nginx 取代 Caddy
- SMTP 郵件伺服器(Kubernetes 部署) — 同為叢集內共用基礎設施服務,部署於
ingress-basicnamespace - Nginx 檔案服務 Server — Nginx autoindex 與 fancyindex 的對等方案
- Nginx Reverse Proxy to Self — Nginx 雙 server block 設計,提供 Caddy 反向代理的參考架構對比
- React + API + DB 服務遠端部署方案 — VPS + docker-compose 全棧部署方案,Caddy 可作為其中的反向代理層