FrankenPHP 默认由内置Caddy直接服务静态资源,不自动对接CDN;需手动配置reverse_proxy或构建时上传至CDN并覆盖ASSET_URL,才能实现CDN加速。

静态资源默认由 Caddy 直接服务,不是走 CDN
FrankenPHP 本身不自动对接 CDN,php_server 指令启用后,所有请求(包括 .css、.js、.png 等)都先经过 Caddy 的路由判断:如果文件存在且在 root 目录下,Caddy 就直接返回;否则才交给 PHP 处理。这和 Nginx 的 try_files 行为一致,但全程不经过外部 CDN。
Caddy 能否代理到 CDN?可以,但得手动配 reverse_proxy
如果你已有 CDN(比如 Cloudflare、CloudFront),想让静态资源走 CDN 回源到 FrankenPHP,需要显式配置反向代理规则,而不是依赖 php_server 自动处理。常见错误是以为加了 php_server 就能“智能分流”,其实它只管 PHP 请求兜底。
-
php_server不会自动识别或重写静态资源 URL,Laravel 生成的mix()或asset()链接仍指向当前域名 - 要让静态资源走 CDN,得在 Caddyfile 中单独为
/build/、/storage/等路径加reverse_proxy,并确保 CDN 的回源 Host 和缓存策略匹配 - 更轻量的做法是:构建时把静态资源上传到 CDN(如用
aws s3 sync),然后通过环境变量覆盖 Laravel 的ASSET_URL,让asset()输出 CDN 域名——这时 FrankenPHP 根本不处理这些请求
为什么别急着上 CDN?Caddy 自带的静态服务能力已经很强
FrankenPHP 内置的 Caddy 支持 encode zstd br gzip、HTTP/3(QUIC)、自动 TLS、强缓存头(Cache-Control: public, max-age=31536000 可手动加),对中小流量站点,本地服务静态资源反而延迟更低、调试更直观。
- CDN 带来的首字节延迟(TTFB)优势,在 FrankenPHP + HTTP/3 + ZSTD 压缩组合下已被大幅压缩
- 若开启
worker模式,PHP 进程常驻,Caddy 同进程读取磁盘文件,没有跨进程 IPC 开销 - 容易踩的坑:开了 CDN 却没关掉 Caddy 的
Etag或Last-Modified,导致 CDN 缓存失效或 304 判定异常
真正要关注的是 Laravel 的静态资源路径与 Caddy 的 root 对齐
很多人发现 CSS 加载 404,不是 CDN 配置问题,而是 Caddy 的 root 没指向 Laravel 的 public/ 目录,或者 php_server 里漏写了 try_files。
立即学习“PHP免费学习笔记(深入)”;
- 确认 Caddyfile 中有
root public/,且该目录下存在index.php和mix.js等文件 -
php_server块必须包含try_files {path} index.php,否则 Caddy 遇到不存在的静态路径会直接 404,不会 fallback 到 PHP - Laravel 的
APP_URL应设为最终对外域名(如https://example.com),而非http://localhost,否则生成的资源链接会错



















