从nginx+fpm迁移到frankenphp
FrankenPHP 是一个把 PHP 解释器“装进”Caddy 的现代应用服务器:一个进程同时干 TLS/HTTP/3、静态资源和 PHP 执行,还支持 103 Early Hints、内置实时推送(Mercure)、以及常驻内存的 Worker 模式来降低延迟。
通俗点说,它把“Nginx + PHP-FPM + 一堆插件”合成了all in one for php web develop。
2025 年 5–6 月,FrankenPHP 获得 PHP 基金会 的“官方支持”,项目代码迁入 PHP 在 GitHub 的官方组织,方便核心贡献者参与、提升长期可持续性。不过日常维护仍由原作者和维护团队负责。
这意味着社区层面把“现代 PHP 的官方应用服务器路线”摆上了台面:更简单的部署形态(Docker/单文件)、更好的开箱体验(HTTP/3、自动 HTTPS)、以及面向高并发的 Worker 模式,都会得到长期投入与生态协同。
想象把「Nginx + PHP-FPM + 证书管理 + 实时推送」塞进一个更省事的“全能小机箱”里,这就是 FrankenPHP:
它把 PHP 解释器嵌进 Caddy Web 服务器,一个进程就能完成 HTTPS/HTTP/3、静态资源、以及 PHP 执行。
结果是:
部署更简单、首屏更快、并发更稳。'
FrankenPHP 的核心功能与优势
1) 一体化:一个进程搞定 Web + PHP
内置 Caddy:自带自动 HTTPS、HTTP/2/HTTP/3、反代与静态资源;配置用 Caddyfile,语法直白。
少一层跳转:不用再 Nginx → php-fpm 走 FastCGI,减少链路复杂度与运维成本。
2) Worker 模式:把框架“常驻内存”,降低每次冷启动
传统 FPM 每个请求都要重新引导框架;Worker 模式让应用常驻内存,请求复用已初始化的容器与依赖,延迟更低、吞吐更高。
Laravel、Symfony、Yii 都已提供官方集成或适配。
注意点:避免静态变量、单例在请求间泄漏状态,必要时做“请求后重置”。
3) 103 Early Hints:让首屏更快“动起来”
支持 HTTP 103 Early Hints:后端慢查询还在跑时,先把 CSS/JS 的预加载提示发给浏览器,页面更早渲染。
官方称可带来最高约 30% 的加载改进(视页面而定)。
4) 内置 Mercure:零 SDK 的实时推送(SSE)
开箱就有 Mercure Hub:后端发布消息,前端通过 Server-Sent Events 直接收到,无需自己搭 WebSocket 服务或写额外 JS SDK。
适合内容更新、系统通知、仪表盘等“轻实时”场景。
5) 单文件分发:把“PHP + Caddy + 你的应用”打包成一个可执行文件
借助 static-php-cli,可以做“静态/几乎静态”构建,生成一个可执行文件:带 PHP 解释器、Caddy、以及你的代码与资源。
用处:边缘节点、无容器环境、内网灰度、离线分发、CI/CD 工件更简洁。
6) 简化的配置与扩展
Caddyfile 就能完成站点、TLS、静态资源缓存、Header 安全策略等常见需求。
需要更多 Caddy 模块?可用 xcaddy 自定义构建,把想要的插件一起编进来。
安装与启动 FrankenPHP
Docker(最快上手,适合本地/生产)
官方镜像同时提供 Debian/Alpine、PHP 8.2/8.3/8.4 多版本。
一行命令即可
1
2
3
4docker run -v $PWD:/app/public \
-p 80:80 -p 443:443 -p 443:443/udp \
dunglas/frankenphp
从源码编译(可定制、推荐常规自建)
需要自己控制 PHP 版本/扩展/构建参数;“动态 PHP 库 + FrankenPHP”是推荐方式。
具体方式可参见官网链接 Compile From Sources.
静态/单文件构建
把 PHP 解释器 + Caddy + FrankenPHP(以及你的应用)打成“一个可执行文件”;
可用于内网、边缘、离线环境分发。
将php业务代码打包进静态可执行文件,虽然看起来不用交付业务php代码,但是并不能起到保护业务代码的作用。
包含了php业务代码的静态可执行文件,在运行时,会将业务代码解压到服务器,在服务器上就可以直接提取业务代码。
构建方式可参见官网链接 Create a Static Build.
FrankenPHP常用命令
frankenphp php-server
用于“开箱即跑”的最小化场景;可叠加 Worker、热重载等选项。不读取 Caddyfile。
1
2
3
4
5
6
7
8
9
10
11
12直接在当前目录提供站点(默认根目录 public/)
frankenphp php-server
启用 Worker(常驻内存)
frankenphp php-server --worker /path/to/worker.php
监听代码变更(glob 支持),自动重启 worker
frankenphp php-server --worker /path/to/worker.php --watch="/app/**/*.php"
(可选)开发期开启本地 HTTPS/HTTP2/HTTP3
frankenphp php-server --https --http-redirect
frankenphp run
用于生产/自定义配置,读取 Caddyfile;支持 -c/–config 指定路径。
1
2
3
4
5在当前目录寻找 Caddyfile(静态二进制也会按此规则查找)
frankenphp run
显式指定 Caddyfile
frankenphp run -c /etc/frankenphp/Caddyfile
frankenphp php-cli
执行单次 CLI 脚本(等价“php your.php”,但走 FrankenPHP 自带的 PHP)。
1
frankenphp php-cli /path/to/script.php
frankenphp reload
仅重载 Caddy 配置(不等同于重启 Worker 逻辑)。适合你修改了 Caddyfile 想无缝应用配置。
1
2
例如容器内重载 Caddy 配置
frankenphp reload -c /etc/frankenphp/Caddyfile
FrankenPHP 配置清单
Caddyfile
Caddyfile告诉 FrankenPHP 如何对外提供服务(域名、端口、TLS、静态资源、路由到 PHP、压缩、日志、安全头、Worker 等)。
Caddyfile在Docker 镜像里通常的路径是 /etc/frankenphp/Caddyfile,独立二进制默认找当前工作目录(可 -c 指定)。
Caddyfile 常用配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
example.com { ... }:定义一个站点(可写多个)。
root * /app/public:站点根目录(通常指向 public/)。
encode zstd br gzip:开启压缩,减小传输体积。
php_server { ... }:一条指令搞定“重写到 index.php + 执行 PHP + 静态文件”,日常首选。
env KEY VAL:给 PHP 传入环境变量(仅该站点)。
worker { file index.php; num 4; }:为该站点启用 Worker(常驻内存),提升吞吐/降低 TTFB。
file_server:提供静态文件(可配长缓存)。
header { ... }:加安全响应头(HSTS、CSP、X-Frame-Options 等)。
log { ... }:访问日志(输出位置、格式、筛选)。
@assets { … } + handle @assets { … }:匹配静态资源并设置缓存头。
全局块 { frankenphp { … } }:引擎层配置(如 php_ini memory_limit 256M、全局 worker、线程数等)。
Caddyfile 示例配置
1 | { |
PHP 配置(php.ini 与扩展)
配置 PHP 运行时的资源限制、功能开关、扩展加载等(与 Web 服务器无关,影响 CLI/Worker/请求处理本身)。
文件位置常见:Docker 下 /usr/local/etc/php/php.ini(可从模板复制)。
独立二进制优先读当前目录或 /etc/frankenphp/php.ini。
静态二进制所需扩展需构建时集成。
FrankenPHP 常用环境变量
SERVER_NAME
设定监听地址与主机名;这些主机名也会用于自动签发的证书。
用法:SERVER_NAME="localhost"(本地 HTTPS),或 SERVER_NAME=":80"(只开 80 端口,常用于前面已有反代/证书时)。
SERVER_ROOT
设置站点根目录,默认是 public/。
用法:SERVER_ROOT="/app/public"。
CADDY_GLOBAL_OPTIONS
向 Caddyfile 的全局块注入配置(无须改 Caddyfile)。
例:启用调试 CADDY_GLOBAL_OPTIONS="debug";或开启 HTTP/1 全双工:
CADDY_GLOBAL_OPTIONS='servers { enable_full_duplex }'。
FRANKENPHP_CONFIG
向全局 frankenphp { … } 指令块注入 FrankenPHP 配置(比如 Worker)。
例:FRANKENPHP_CONFIG='worker /app/public/index.php 4'。也可配合默认模板把多行片段注入。
PHP_INI_SCAN_DIR
追加加载的 *.ini 目录(PHP 自带能力),便于把自定义 php.ini 片段随容器/环境注入。
1 | docker run -v $PWD:/app \ |
Worker 模式
Worker 模式让框架常驻内存,显著降低 TTFB/CPU 抖动。两种写法:
全局块 Worker:
1 | { |
直接在站点里:
1 | example.com { |
启用 Caddy admin 后,通过POST /frankenphp/workers/restart 可优雅重启全部 worker。
也可在开发期用 –watch 自动重启。
reference:
Author: GaoYuan
Link: https://blog.gaoyuan.xyz/2025/09/20/from-nginx-fpm-to-frankenphp/
Use Soulens: Know Destiny, Chart Journey
License: 知识共享署名-非商业性使用 4.0 国际许可协议