静态托管与 PHP FastCGI
用墨守替代 Nginx / Caddy:静态目录托管(SPA 回退、预压缩、点文件拒绝)与 php-fpm 回源(WordPress / ThinkPHP)。
墨守不只是挡在 Nginx 前面——它可以直接替掉 Nginx / Caddy。站点的回源类型有三种,互斥三选一:反向代理(upstream)、静态目录托管(static)、PHP FastCGI(fastcgi)。简单部署场景下,一个静态站或一个 WordPress 站不再需要另装 Web 服务器。
#静态目录托管
在「站点管理 → 新增站点」把回源类型选「静态」,填根目录即可。HTTP 语义走标准实现:ETag / 304、Range 断点续传、If-Modified-Since、sendfile 一应俱全。
| 字段 / 控件 | 默认 / 示例 | 说明 |
|---|---|---|
root | (必填) | 静态根目录,如 /var/www/example。 |
index | ["index.html"] | 目录索引文件。 |
spa_fallback | (关) | 无扩展名且未命中的路径回退到该目标(如 /index.html)。带扩展名的资源缺失仍返回 404,不会把 JS 请求回退成 HTML。 |
precompressed | true | 优先返回同名的 .br / .zst / .gz 预压缩文件,按 Accept-Encoding 协商。 |
compress_on_the_fly | false | 没有预压缩文件时,对可压缩类型实时 gzip(brotli 请用预压缩文件)。 |
cache_control | [] | 按 glob 设 Cache-Control,如给 /assets/* 设长缓存(仅配置文件)。 |
error_pages | {} | 自定义错误页,如 {"404": "/404.html"}(root 内,仅配置文件)。 |
hidden_deny | true | 默认拒绝点文件(.git / .env / .htaccess / .user.ini…),except 可放行如 .well-known。 |
follow_symlinks | false | 默认不跟随跳出 root 的符号链接。 |
dir_list | false | 目录列表。 |
静态站点配置
sites:
- host: "www.example.com"
static:
root: "/var/www/example"
spa_fallback: "/index.html" # SPA 应用
precompressed: true命中真实静态文件的 GET / HEAD 走快速路径:就地发文件,跳过语义检测与智能缓存。过载保护、访问控制、限流、Bot 防护、等候室这些外层照常先跑。受 认证网关 管辖的站点不走快速路径,否则静态文件会绕过登录被直接读走。
#路径安全
静态服务最经典的漏洞是路径穿越。墨守的解析顺序是固定的:
- 1NUL 与非法 UTF-8 → 400先挡掉畸形字节。
- 2解编码绊线 → 400与检测器同款的归一化解码,
%2e%2e、双重编码、overlong、反斜杠等../变体一律拒绝。 - 3结构性容纳
path.Clean根锚定 + join + 相对路径复检,即使绊线没响也逃不出 root。 - 4点文件与符号链接点文件拒绝;符号链接校验最终目标仍在 root 内。
响应始终带
X-Content-Type-Options: nosniff,Content-Type 按扩展名给出、不做内容嗅探——上传的 .jpg 即使内含 PHP 也只会当图片发。#PHP FastCGI(替代 Nginx + php-fpm)
回源类型选「PHP」,填 php-fpm 地址与站点根目录。行为对齐 Caddy 的 php_fastcgi:真实静态文件本地直发,.php 与前端控制器交给 php-fpm。
WordPress 站点
sites:
- host: "blog.example.com"
fastcgi:
address: "unix:/run/php/php-fpm.sock" # 或 tcp:127.0.0.1:9000
root: "/var/www/wordpress"
index: "index.php"ThinkPHP / 通用前端控制器
sites:
- host: "app.example.com"
fastcgi:
address: "tcp:127.0.0.1:9000"
root: "/var/www/app/public" # ThinkPHP 指向 public 目录
index: "index.php"控制台里更省事:站点管理 → 新增站点 → 回源类型选「PHP」→ 点「WordPress」或「ThinkPHP」一键模板 → 核对根目录与 php-fpm 地址 → 保存,即时生效。
try_files 决策顺序
- 1安全清理路径穿越直接 404。
- 2分割脚本与 PATH_INFO
/x.php/y→ 脚本/x.php+ PATH_INFO/y。 - 3脚本真实存在 → 交 php-fpm这一步是安全不变式的关键。
- 4是真实的非脚本文件 → 本地静态发送图片、CSS、JS 走静态路径。
- 5是目录且有 index.php → 交 php-fpm
- 6前端控制器回退 → root 的 index.php伪静态永久链接走这条;
REQUEST_URI原样传给 PHP,由 WordPress / ThinkPHP 自行路由。 - 7都不匹配 → 404
PATH_INFO 漏洞已被根除安全不变式:交给 FastCGI 的
SCRIPT_FILENAME 永远是一个真实存在的 .php 文件。伪造 PATH_INFO 后缀(/uploads/evil.jpg/x.php,而 x.php 并不存在)不会让非脚本文件被执行——经典的 cgi.fix_pathinfo / Nginx .jpg/.php 漏洞在代理层就被根除。root 之外的 SCRIPT_FILENAME 一律拒绝。动态请求(走 FastCGI 的)必走完整八层检测链路,绝不走静态快速路径。只有真实静态文件命中才会 fast-path。
权限提示:php-fpm 需要能读 root 目录;若用 unix socket,墨守进程需对该 socket 有读写权限(同组或 0666)。systemd 沙箱下把 socket 目录加进
ReadWritePaths。#明确不支持 .htaccess
墨守不读取、不执行 .htaccess / .user.ini(且默认拒绝它们对外响应)。Apache 伪静态请用 CMS 后台生成的 Nginx 版规则,按 伪静态 URL 重写 转换成墨守格式。
部署完静态站或 PHP 站,强烈建议再开一道 静态内容防篡改——对 PHP 站尤其能挡 WebShell。
