Context
本站是文档与运维内容:用来阅读、检索、归档的页面。动态应用服务器可以渲染模板、管理会话或提供交互组件,但这些是可选能力,不是当前需求。内容本身对服务器端状态、按用户的认证逻辑或客户端渲染都没有要求。
Decision
用 Caddy 将一个预构建的静态树作为站点提供服务,通过受控的发布切换选择一个不可变发布目录。目录发布 ADR 解释了切换方式及其跨请求限制。边缘后面没有应用服务器、没有脚本通道、没有数据库。
浏览器 ──HTTPS──► Caddy ──文件系统读取──► public/ 发布树
预期的浏览器无脚本契约由响应头(script-src 'none')下发,并由拒绝可执行脚本与残缺产物的构建检查支持。CSP 由浏览器执行,不能证明没有应用服务器。构建输出是 public/,其中包括生成的页面和从源 static/ 目录复制的文件。
后果
- 发布更简单: 内容产物没有应用状态或数据库 schema 要迁移。发布切换、缓存行为与回滚仍须验证。
- 威胁面更窄: 请求路径没有应用模板求值器或数据库查询层。Caddy 和浏览器仍会解析不可信输入,生成器与依赖仍在构建时执行。
- 缓存可检查: 不可变发布文件有稳定字节。校验器、压缩变体与新鲜度指令仍需正确服务器配置。
- 接受的取舍: 没有脚本驱动的交互、认证个性化或每用户 HTML。原生文档交互仍然可用。若确实需要,应作为独立的服务来组合,而不是并进这棵树。
仍然存在的边界
只发布生成树,不发布仓库根、构建凭据或私有内容。Caddy 的 root 不是文件系统沙箱:根内的符号链接可能暴露根外目标。发布前应检查产物符号链接、权限与错误路由。无脚本 CSP 不会让 HTML 注入无害,也不能保护被公开的机密文件。
持续更新服务器,验证实际公共响应,并保留经过测试的上一版。这些运维责任不会随应用层的移除而消失。仓库记录的是预期架构与示例配置,不是证明当前生产主机没有其他服务的资产清单。
为什么它胜过替代方案
动态层带来一个运行时、一个状态边界和一条更慢的编辑路径。对价值在文档本身的内容,这笔成本买来了内容用不到的能力。静态服务没有牺牲站点需要的任何东西,同时移除了只会让发布与安全边界变复杂的部分。
来源
- Caddy 文档:
file_server,在没有应用层的情况下提供静态根目录,已核验 2026-10-15。 - MDN:内容安全策略,浏览器资源与执行策略,已核验 2026-10-15。