03 - 静态文件服务 / Static File Serving
静态文件服务 / Static File Serving
🟢 基础 / Basics
最简配置
localhost {
root * /var/www/html
file_server
}
root 指定文件根目录,file_server 启用静态文件服务。
指定端口
:8080 {
root * /home/user/website
file_server
}
多站点
site-a.example.com {
root * /var/www/site-a
file_server
}
site-b.example.com {
root * /var/www/site-b
file_server
}
🟡 进阶 / Intermediate
启用目录浏览
localhost {
root * /var/www/files
file_server browse
}
browse 参数启用目录列表,适合文件下载站。
自定义浏览模板
localhost {
root * /var/www/files
file_server browse /path/to/custom-template.html
}
自定义模板使用 Go template 语法,变量包括:
.Name— 文件名.Size— 文件大小.ModTime— 修改时间.IsDir— 是否为目录
处理 SPA(单页应用)
React / Vue / Svelte 等 SPA 框架需要所有路径回退到 index.html:
localhost {
root * /var/www/spa/dist
try_files {path} /index.html
file_server
}
try_files 会先查找请求路径对应的文件,找不到就回退到 /index.html。
配置 Cache-Control
localhost {
root * /var/www/static
@static {
path *.css *.js *.png *.jpg *.gif *.svg *.woff2
}
header @static Cache-Control "public, max-age=31536000, immutable"
@html {
path *.html
}
header @html Cache-Control "no-cache"
file_server
}
路径重写(Path Rewriting)
localhost {
root * /var/www
# 去掉 .html 后缀
@noext {
not path */*
not file {path}
}
rewrite @noext {path}.html
file_server
}
这样 /about 会自动匹配 /about.html。
禁止访问隐藏文件
localhost {
root * /var/www
@hidden {
path */.*
}
respond @hidden 403
file_server
}
🔴 高级 / Advanced
file_server 的内部机制
file_server 是一个 HTTP handler module,内部流程:
请求 /css/style.css
│
▼
Etag 计算 ──→ 如果 If-None-Match 匹配 → 304 Not Modified
│
▼
检查文件是否存在
│
├─ 存在 → 读取文件 → Content-Type 检测 → 200
│
└─ 不存在 → try_files / 404
Precompressed 文件支持
localhost {
root * /var/www/dist
file_server {
precompressed gzip br zstd
}
encode gzip zstd
}
precompressed 让 Caddy 直接发送预压缩好的 .gz / .br / .zst 文件,避免运行时压缩开销。
构建时生成预压缩文件:
# gzip
find /var/www/dist -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) \
-exec gzip -k {} \;
# brotli
find /var/www/dist -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) \
-exec brotli {} \;
结合模板引擎
Caddy 内置 templates 模块,可以在 HTML 中嵌入服务端逻辑:
localhost {
root * /var/www
templates
file_server
}
HTML 文件中:
<h1>当前时间:{{ now }}</h1>
<p>请求路径:{{ .Request.URL.Path }}</p>
<p>随机数:{{ randInt 1 100 }}</p>
自定义 MIME 类型
Caddy 根据文件扩展名自动检测 Content-Type,如果遇到未知类型:
localhost {
root * /var/www
header Content-Type "application/octet-stream" {
path *.bin
}
file_server
}
或修改 Caddy 内置的 MIME 数据库(需自编译)。
大文件分片 / Range Requests
Caddy 默认支持 Range 请求头,无需额外配置:
# 下载前 1024 字节
curl -H "Range: bytes=0-1023" https://example.com/large-file.zip -o part1
# 测试是否支持
curl -I https://example.com/large-file.zip | grep -i accept-ranges
# Accept-Ranges: bytes
视频播放器依赖 Range 请求实现 seek 功能,Caddy 开箱即用。
并发限流与静态文件
高流量场景下,静态文件服务可能需要配合限流:
{
order rate_limit before file_server
}
import /etc/caddy/rate_limit.conf
localhost {
root * /var/www
rate_limit {
zone static_zone {
key {remote_host}
events 100
window 1m
}
}
file_server
}
小结 / Summary
| 层级 | 内容 |
|---|---|
| 🟢 基础 | root + file_server,多站点 |
| 🟡 进阶 | browse、SPA try_files、Cache-Control、路径重写 |
| 🔴 高级 | precompressed、模板引擎、Range 请求、MIME 定制 |