静态资源404主因是FrankenPHP未正确服务public/目录:需确保Caddyfile中root与php_server路径均精准指向public/,且项目结构合规、fileinfo扩展启用、日志验证处理流向。

静态资源返回 404,通常不是 Laravel 路由没匹配,而是 FrankenPHP 没正确识别或服务 public/ 目录下的文件。它默认只把 public/ 当作 Web 根目录,但配置稍有偏差就会跳过静态路径、直接交给 PHP 处理,而 Laravel 的 index.php 又不负责返回 JS/CSS/IMG,结果就是 404。
确认 Caddyfile 中 root 和 php_server 的路径是否一致
FrankenPHP 依赖 Caddyfile 明确声明网站根目录,并让 php_server 知道从哪开始找 PHP 文件和静态资源。两者必须都指向 public/,且路径写法要准确:
-
root public/:表示 Web 根是当前目录下的
public/子目录(不是./public,也不是/app/public) -
php_server { try_files {path} index.php }:其中
{path}是相对root的路径,所以它会先查public/js/app.js这类文件是否存在 - 如果
root写成root /app/public(绝对路径),但容器里实际挂载位置是/app,而public/在里面,那 Caddy 就找不到文件
检查项目结构是否符合预期
FrankenPHP 官方镜像和二进制都默认以 public/ 为 Web 入口。确保你的 Laravel 项目根目录下确实存在 public/,且里面包含 index.php、css/、js/ 等子目录和文件:
- 运行
ls -l public/,确认index.php和常用静态资源都在 - 如果用 Docker,确认挂载命令是
-v $PWD:/app,而不是-v $PWD/public:/app—— 后者会让root public/实际变成/app/public/,多了一层 - 独立二进制运行时,Caddyfile 必须放在 Laravel 项目根目录(即
composer.json所在处),不能放在public/里
验证 PHP 扩展是否影响静态文件判断
某些 PHP 扩展(如 opcache 或自定义重写模块)可能干扰 try_files 行为,但更常见的是 fileinfo 缺失导致 Caddy 无法正确识别 MIME 类型,进而跳过静态服务逻辑:
立即学习“PHP免费学习笔记(深入)”;
- 执行
frankenphp php-cli -m | grep fileinfo(二进制方式)或docker exec -it your-container frankenphp php-cli -m | grep fileinfo(Docker 方式) - 若无输出,说明
fileinfo未启用;Docker 用户可在构建镜像时加RUN install-php-extensions fileinfo,二进制用户需重新下载带该扩展的版本或手动编译 -
mime_type推断失败时,Caddy 可能放弃静态处理,直接 fallback 到index.php,而 Laravel 路由又没定义/js/app.js,最终 404
临时加一行 log 查看请求真实走向
在 Caddyfile 的站点块里加一条日志指令,确认请求到底被谁处理了:
log { output stdout format console }然后启动 FrankenPHP,访问一个 JS 文件(如 http://localhost/js/app.js),观察终端输出:
- 如果日志里出现
handled by php_server,说明try_files没命中,得回头检查路径或文件是否存在 - 如果出现
handled by file_server但仍是 404,大概率是文件权限问题(如容器内 UID 不匹配导致读不到)或路径拼写错误(比如大小写、多余斜杠)



















