必须为每个正式域名配置独立 server 块,共用块会导致 root 错乱、php 脚本跨站执行及静态文件错误返回;frankenphp 依赖 caddyfile 的 server 块作用域实现隔离,非虚拟主机或子目录机制。

可以,但必须用独立 server 块配每个域名,共用块会导致 root 错乱、PHP 脚本跨站执行,甚至静态文件被错误返回。
每个域名必须单独写一个 server 块
FrankenPHP 的作用域隔离完全依赖 Caddyfile 的 server 块边界,不是靠虚拟主机或子目录。把多个域名写在同一个块里,例如:
example.com, www.example.com { root /var/www/app/public php_server }
会导致两个域名都指向同一目录,根本做不到“各跑各的”。正确做法是拆成两个块:
-
example.com块里root指向/var/www/site-a/public -
www.example.com块里root指向/var/www/site-b/public(或相同目录,但这是你主动控制的) - 通配符如
*.example.com可以复用一个块,但注意 Let’s Encrypt 泛域名证书需 DNS-01 验证
root 必须精确到 public/ 目录
Laravel、Symfony 等框架的入口统一放在 public/ 下,root 若指向项目根目录(如 /var/www/app),则 /index.php 会 404,且可能暴露敏感文件(如 .env)。
- 正确:
root * /var/www/laravel-app/public - 错误:
root * /var/www/laravel-app或root * /var/www/laravel-app/public/(末尾斜杠可能触发路径归一化异常) -
root后面加*是显式启用路径匹配,推荐写上
php_server 的 try_files 要用相对路径
php_server 的 try_files 参数解析上下文是当前 root,不是文件系统绝对路径。写错会导致 404 或 FrankenPHP 启动失败。
- 正确:
try_files {path} /index.php(/index.php表示从root开始找) - 错误:
try_files {path} /var/www/app/public/index.php(绝对路径会被拒绝) - 如果框架入口不是
index.php(如 ThinkPHP 的index.php在项目根),那root就得指向包含它的目录,而非public/
DNS、端口、证书三者必须同时就位
Caddy 自动申请 HTTPS 证书的前提很硬:域名 DNS 解析必须已生效、服务器 80/443 端口必须开放、防火墙放行。缺一不可。
- 本地测试别用
localhost:8080,它不带 Host 头,Caddy 无法路由;改/etc/hosts加127.0.0.1 site-a.test,再用site-a.test测试 - 若暂时不想强制 HTTPS,可在块内加:
redir https://{http.request.hostport}{http.request.uri} 301来禁用重定向 - 证书失败时看
caddy logs,常见原因是 DNS 解析未全球生效,或云厂商安全组没开 80 端口
最容易被忽略的是:所有 server 块共享同一个 FrankenPHP 进程和线程池,但彼此完全隔离——只要 root 和 php_server 没写错位置,就不会出现跨域加载或配置污染。一旦发现某站点 PHP 文件被另一个站点执行,第一反应就该检查是否误把多个域名塞进了一个块里。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











