核心原因是FrankenPHP未正确服务public/目录:需确保Caddyfile中root与php_server均精准指向public/,项目结构合规、fileinfo扩展启用,并用curl验证静态文件是否由Caddy直供。

FrankenPHP 1.5 静态资源返回 404,核心原因不是 Laravel 路由没生效,而是 FrankenPHP(通过 Caddy)根本没把 .js、.css、图片等请求当作静态文件处理——它直接转发给了 index.php,而 PHP 入口不负责返回这些文件,结果就是 404。
确认 Caddyfile 的 root 和 php_server 路径是否精准指向 public/
FrankenPHP 依赖 Caddyfile 明确声明 Web 根目录,并让 php_server 知道从哪找静态资源和 PHP 文件。两者必须严格一致且路径准确:
-
root public/:表示 Web 根是当前目录下的public/子目录(不能写成./public、/app/public或public不带斜杠) -
php_server { try_files {path} /index.php?{query} }:其中{path}是相对于root的路径,Caddy 会先查public/js/app.js是否存在 - 如果
root写成绝对路径(如root /app/public),但 Docker 挂载的是-v $PWD:/app,实际文件路径就变成/app/public/public/js/app.js,Caddy 自然找不到
检查项目结构与挂载方式是否合规
FrankenPHP 官方镜像和二进制默认以 public/ 为 Web 入口,这点不可妥协:
- 在项目根目录运行
ls -l public/,确认index.php、css/、js/、images/等都存在 - Docker 启动时,挂载命令必须是
-v $PWD:/app(整个项目根挂载),而不是-v $PWD/public:/app(否则root public/实际指向的是/app/public/,多出一层嵌套) - Caddyfile 必须放在项目根目录(即
composer.json所在处),不能放在public/里
验证 fileinfo 扩展是否启用
fileinfo 缺失会导致 Caddy 无法正确识别文件 MIME 类型,进而跳过静态服务逻辑,直接 fallback 到 index.php:
立即学习“PHP免费学习笔记(深入)”;
- 执行
frankenphp php-cli -m | grep fileinfo(二进制方式)或docker exec -it your-container frankenphp php-cli -m | grep fileinfo(Docker 方式) - 若无输出,说明未启用;Docker 用户可在构建镜像时加
RUN install-php-extensions fileinfo - 二进制用户需下载带该扩展的 FrankenPHP 版本(如官方 release 中标注
with-fileinfo的包)
用 curl 直接验证静态文件是否由 Caddy 直供
别只看页面能不能打开,要确认响应头是否干净:
- 在
public/下放一个测试文件:echo "static ok" > public/hello.txt - 执行
curl -I http://localhost:8000/hello.txt - 检查响应:状态码应为
200,Content-Type应为text/plain; charset=utf-8,且响应头中不应出现X-Powered-By: PHP或X-FrankenPHP - 如果返回 404 或内容类型错误,说明静态服务链路尚未打通



















