跳到正文

静态站点

example.com {
root * /var/www/html
file_server
}

root * 的星号是必须的——它表示后面那个值是一个路径列表,而不是字面量。这写法初看很怪,但 Caddyfile 就这样。

前端应用刷新 /settings 直接404,因为构建产物里只有 index.html。解决:

example.com {
root * /var/www/dist
try_files {path} /index.html
file_server
}

try_files 依次检查,第一个存在的就返回;全都不存在则回退到 /index.html。

有静态资源前缀时更精确一点:

@assets path /assets/* /favicon.ico /manifest.json
handle @assets {
root * /var/www/dist
file_server
}
handle {
root * /var/www/dist
try_files {path} /index.html
file_server
}

这样 /assets/ 下的文件不存在就是真404,而不是被 SPA 回退吞掉。

带 hash 的构建产物可以永久缓存,HTML 入口不能:

example.com {
root * /var/www/dist
@static path /assets/* /_astro/* /fonts/*
header @static Cache-Control "public, max-age=31536000, immutable"
@html path / /index.html
header @html Cache-Control "no-cache"
file_server
}

no-cache 不是「不缓存」,是「缓存了也要回源校验」。入口 HTML 用它,用户的版本切换才不会被缓存卡住。

example.com {
root * /var/www/dist
encode gzip zstd
file_server
}
uploads.example.com {
root * /srv/uploads
file_server browse
}

browse 会生成目录列表页,方便临时当网盘用。

upload.example.com {
root * /srv/uploads
request_body {
max_size 100MB
}
file_server
}
example.com {
root * /var/www/html
file_server {
hide .git
hide *.bak
}
}

hide 可以挡住敏感文件被直接下载——比如误传上去的 .env。

(a.example.com) {
root * /var/www/a
file_server
}
(b.example.com) {
root * /var/www/b
file_server
}
*.example.com {
root * /var/www/default
file_server
}

括号片段 + import 复用,比复制粘贴可靠得多。

与框架的 dev 模式配合

章节「与框架的 dev 模式配合」
:5173 {
reverse_proxy localhost:5173
}

Vite / Next.js / Nuxt 的 dev server 固定端口,Caddy 当一层入口,Cookie 域名就能统一在 .example.com 下了。