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
4
docker 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
auto_https off
# 全局设置
http_port 80
auto_https disable_redirects
}

a.test.net:80 {
root /home/project/public
# 日志
log {
output file /var/log/frankenphp-access.log
format json
}

# 自定义 Header
# header {
# X-Frame-Options "DENY"
# X-Content-Type-Options "nosniff"
# }

try_files {path} {path}/ /bootstrap.php?{query}

php_server {
root /homeh/project/public/ # 允许更好的缓存
env run_mode "development"
env REQUEST_PROJECT "Account"
}
}

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
2
3
4
5
6
7
8
docker run -v $PWD:/app \
-e SERVER_NAME=":80" \
-e SERVER_ROOT="/app/public" \
-e CADDY_GLOBAL_OPTIONS="debug" \
-e FRANKENPHP_CONFIG="worker /app/public/index.php 4" \
-p 80:80 -p 443:443 -p 443:443/udp \
dunglas/frankenphp

Worker 模式

Worker 模式让框架常驻内存,显著降低 TTFB/CPU 抖动。两种写法:

全局块 Worker:

1
2
3
4
5
6
7
8
9
{
frankenphp {
worker {
file /app/public/index.php
num 4 # worker 数,按核数调
env APP_ENV production
}
}
}

直接在站点里:

1
2
3
4
5
6
example.com {
root * /app/public
php_server {
worker index.php 4 # 指定 worker 与并发数
}
}

启用 Caddy admin 后,通过POST /frankenphp/workers/restart 可优雅重启全部 worker。
也可在开发期用 –watch 自动重启。

reference:

[^1] https://frankenphp.dev/docs/