frankenphp 无传统 documentroot,其 web 根由 caddy 的 root 指令显式指定(必须为绝对路径且指向 public/),php_server 需与 root 同级生效;项目其余目录可放任意位置,由 public/index.php 显式加载。

FrankenPHP 的 root 和项目目录不是一回事
FrankenPHP 没有传统意义上的“网站根目录”配置项,它不读 DocumentRoot 或 root 指令。它的行为由 Caddy 的 php_server 指令和当前工作目录共同决定:Caddy 默认把当前运行 frankenphp 命令的目录当作 Web 可访问的根(即能被 GET /index.php 访问到的起点),而 PHP 项目的实际结构(比如 app/、config/)应放在这个目录之下或之外——只要代码里能正确引用就行。
public 目录必须是 Caddy 的 root
如果你的 ThinkPHP/Laravel 项目习惯把 public/ 当作 Web 入口,那就必须让 Caddy 的 root 指向它,否则 index.php 找不到,静态资源 404,路由全挂。常见错误是把整个项目根目录(含 app/、public/)设为 Caddy root,结果浏览器直接能列目录或访问到 config/database.php。
-
root必须显式写在 Caddyfile 里,不能依赖默认值;例如:root * /var/www/myapp/public - 路径必须是绝对路径,Windows 下用正斜杠:
root * D:/projects/myapp/public - 确保该目录存在且
index.php在其中,否则php_server不会触发 - 不要把
php_server放在全局块里——它只对匹配的route生效,必须和root同级或嵌套在handle中
项目其余部分放哪?怎么加载?
框架代码(app/、config/、vendor/)可以放在 public/ 外任意位置,只要 public/index.php 能通过相对路径或常量找到它们。FrankenPHP 不干涉这部分逻辑,它只负责把 HTTP 请求交给 PHP 执行。
- 推荐结构:
/var/www/myapp/下放完整项目,public/是子目录,Caddyroot指向/var/www/myapp/public - 如果想隔离,把
app/移到/opt/myapp/app,就在public/index.php开头加:define('APP_PATH', '/opt/myapp/app'); - 避免用
dirname(__DIR__)向上跳——软链接环境下返回物理路径,改用显式定义的常量更稳 - Composer 自动加载靠
vendor/autoload.php,只要路径对,FrankenPHP 和 PHP-FPM 行为一致
Caddyfile 配错导致 404 或 500 的典型表现
FrankenPHP 报错不直接说“root 配错了”,而是表现为请求无响应、空白页、或 Caddy 返回 404(非 PHP 错误)。关键要分清是 Caddy 拦截失败,还是 PHP 运行出错。
- 访问
http://localhost显示404 Not Found:Caddy 没找到匹配的root或php_server规则,检查 Caddyfile 是否有root *+php_server组合 - 访问
/index.php显示下载或源码:Caddy 没触发php_server,确认没漏掉php_server行,且没被其他handle覆盖 - 访问报
500 Internal Server Error且日志里有require(): failed to open stream:PHP 代码路径错了,和 FrankenPHP 无关,回退查public/index.php里的 require 路径 - 静态资源(CSS/JS)404:Caddy 的
root指向了项目根而非public/,或者路径里少写了public/这一级
FrankenPHP 的配置重心不在“根目录”,而在“谁来当 Web 入口”和“PHP 怎么加载项目”。别试图把它往 Apache 的 DocumentRoot 模型里套,先理清 public/ 是不是真正暴露给用户的唯一入口,再决定 Caddy 的 root 和 PHP 的自动加载路径怎么配合。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











