frankenphp默认仅将index.php或php_server匹配的请求交php处理,其余路径因caddy路由优先级(先静态后动态)未显式配置fallback而返回404;需在caddyfile中用try_files、handle及file_server except等确保非静态资源正确落入php。

为什么静态文件或特定路径没进 PHP 处理器
FrankenPHP 默认只把 index.php 或匹配 php_server 指令的请求交给 PHP 执行,其余路径(比如 /css/app.css、/api/v1/health)可能被 Caddy 直接返回 404 或 403,根本没触达 Laravel 入口。这不是 bug,是 Caddy 的路由优先级行为:它先找静态文件,再 fallback 到 PHP —— 但这个 fallback 必须显式配置。
Caddyfile 中 php_server 必须覆盖全部 PHP 路由入口
很多人只写了一行 php_server,以为全局生效,其实它只作用于当前站点块的默认匹配规则。Laravel 需要所有非静态资源都落到 public/index.php,否则路由解析失败。
- 错误写法(仅处理根路径):
localhost {<br> php_server<br>} - 正确写法(显式 fallback):
localhost {<br> root * public/<br> php_server<br> file_server<br> handle_path /api/* {<br> php_server<br> }<br> handle {<br> try_files {path} {path}/ /index.php?{query}<br> php_server<br> }<br>} - 更稳妥的 Laravel 适配写法(官方推荐):
localhost {<br> root * public/<br> php_server<br> file_server<br> @notStatic {<br> not path *.css *.js *.png *.jpg *.gif *.svg *.woff2<br> }<br> handle @notStatic {<br> try_files {path} /index.php?{query}<br> }<br>}
检查是否被 file_server 提前拦截了
file_server 在 Caddy 中默认启用且优先级高于 php_server。如果你在 php_server 前写了 file_server,又没加 except 排除,Caddy 就会直接尝试读取 public/api/v1/health 这类路径 —— 显然不存在,于是返回 404,压根不进 PHP。
- 确认
file_server是否带except:file_server except /api/* /admin/*
- 或者把
file_server放在php_server后面,并用handle明确分组 - 临时验证方法:注释掉
file_server,只留php_server和try_files,看路径是否能进index.php
public/ 下有同名目录或文件导致路由被吞
FrankenPHP(和传统 Nginx/FPM 一样)遵循「先静态后动态」原则。如果 public/api 是个真实目录,而你期望 /api/v1/health 走 Laravel 路由,那 Caddy 会在 file_server 阶段就返回 404(因为 public/api/v1/health 不存在),根本不会 fallback。
- 检查
public/目录下是否意外存在与路由同名的子目录(如public/api/、public/admin/) - 运行
ls -la public/api确认它不是真实目录;如果是,删掉或重命名 - 开发期可加日志快速定位:
log {<br> output stdout<br> format json<br>},然后观察请求是否进入php_server模块(日志里会出现"handler":"php_server")
FrankenPHP 的路由逻辑藏在 Caddy 的匹配顺序里,而不是 PHP 层。最容易被忽略的是 try_files 没写、file_server 没排除、以及 public/ 下残留的同名路径 —— 这三处不动代码也能让整个路由链路静默失效。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











