FrankenPHP 装法与运行:Go 写的 PHP 应用服务器,php-server 与 Worker 怎么配
项目地址:github.com/dunglas/frankenphp,官网:frankenphp.dev。
它是什么
FrankenPHP 是一个用 Go 编写的 PHP 应用服务器,直接构建在 Caddy 之上。PHP 解释器通过 CGO 以原生方式嵌入 Go 运行时,省掉了 PHP-FPM 与 Web 服务器之间的进程间通信。它可以服务任意 PHP 应用,也能作为独立的 Go 库使用:只要应用基于 net/http,就可以把 PHP 嵌进去。
核心特性:
- Early Hints(103 状态码):PHP 响应完整生成前提前推送关键资源。
- Worker 模式:常驻内存的 PHP Worker。
- 实时能力:内置 Mercure.rocks。
- 热重载:文件变更后自动重载 PHP 线程。
- 自动 HTTPS 与 HTTP/2、HTTP/3:继承 Caddy 的证书管理与协议支持。
安装
一键脚本(Linux / macOS):
curl https://frankenphp.dev/install.sh | sh
Windows PowerShell:
irm https://frankenphp.dev/install.ps1 | iex
独立二进制:官方为 Linux、macOS、Windows 提供免安装二进制,内置 PHP 8.5;Linux 版为静态链接,不依赖系统库。
rpm(dnf):
sudo dnf install https://rpm.henderkes.com/static-php-1-0.noarch.rpm
sudo dnf module enable php-zts:static-8.5 # 8.2–8.5 可用
sudo dnf install frankenphp
扩展用 sudo dnf install php-zts-;默认未提供的走 PIE:
sudo dnf install pie-zts && sudo pie-zts install asgrim/example-pie-extension
deb(apt):
VERSION=85 # 82–85 可用
sudo curl https://pkg.henderkes.com/api/packages/${VERSION}/debian/repository.key -o /etc/apt/keyrings/static-php${VERSION}.asc
echo "deb [signed-by=/etc/apt/keyrings/static-php${VERSION}.asc] https://pkg.henderkes.com/api/packages/${VERSION}/debian php-zts main" | sudo tee -a /etc/apt/sources.list.d/static-php${VERSION}.list
sudo apt update && sudo apt install frankenphp
apk(Alpine):
VERSION=85
echo "https://pkg.henderkes.com/api/packages/${VERSION}/alpine/main/php-zts" | sudo tee -a /etc/apk/repositories
KEYFILE=$(curl -sJOw '%{filename_effective}' https://pkg.henderkes.com/api/packages/${VERSION}/alpine/key)
sudo mv ${KEYFILE} /etc/apk/keys/ && sudo apk update && sudo apk add frankenphp
Homebrew:
brew install dunglas/frankenphp/frankenphp
扩展统一通过 PIE 安装。仓库 package/ 目录提供 debian / rhel / alpine 三种打包平台的服务文件,deb、rpm 包内置 systemd 服务单元。
两条核心命令
frankenphp php-server 启动生产级 PHP 服务器。服务当前目录的 PHP 应用直接跑:
frankenphp php-server
它本质是动态构造 Caddy 配置并启动 HTTP 服务。没有 --domain 时默认监听 :80,请求按「目录重定向 → 重写到 index.php → PHP 执行 → 静态文件服务」处理。
常用参数:
--domain/-d:指定域名启用 HTTPS,自动切 443 并签发证书,需要先配好 A/AAAA 记录。--root/-r:网站根目录。--listen/-l:自定义监听地址,默认:80,指定域名时为 443。--worker/-w:启用 Worker 模式,可逗号指定 Worker 数量。--watch:监听文件变更触发热重载。--access-log/-a:启用访问日志。--debug/-v:详细调试日志。--mercure/-m:启用内置 Mercure Hub。--no-compress:关闭压缩。
默认不加 --no-compress 时会自动启用 zstd、br、gzip,按 zstd → br → gzip 的优先级协商。
frankenphp php-cli 以 CLI SAPI 方式执行 PHP 脚本:
frankenphp php-cli /path/to/your/script.php
它保持 PHP CLI SAPI 的参数语义,其余参数原样透传,返回脚本退出码。可以把 frankenphp php-cli 当作 php 命令的替代品,用来跑 Composer、Artisan 等工具。
deb / rpm 包安装后可用 systemd 启动:
sudo systemctl start frankenphp
Docker 部署
docker run -v .:/app/public \
-p 80:80 -p 443:443 -p 443:443/udp \
dunglas/frankenphp
随后访问 https://localhost。不要用 https://127.0.0.1,用 https://localhost 并接受自签名证书。换域名用 SERVER_NAME 环境变量。443/udp 用于 HTTP/3(QUIC)。容器内默认使用 caddy/frankenphp/Caddyfile 作为配置模板。
配置体系
FrankenPHP、Caddy 以及内置的 Mercure、Vulcain 模块都使用 Caddy 支持的配置格式,最常用的是 Caddyfile。默认在当前目录查找 Caddyfile,也可用 -c / --config 指定。
最小可用 Caddyfile:
localhost {
encode zstd br gzip
php_server
}
php_server 等价于 php 指令加静态文件服务。
全局 frankenphp 配置块(Caddy 全局选项):
{
frankenphp {
num_threads # PHP 线程数,默认 CPU 数 × 2
max_threads # 运行时额外启动上限,默认 num_threads,可设 auto
max_wait_time # 请求等待空闲线程的最大超时
max_idle_time # 自动扩容线程空闲多久后停用,默认 5s
max_requests # 实验性:线程处理多少请求后重启,缓解内存泄漏,默认 0
php_ini # 设置 php.ini 指令
worker {
file
# Worker 脚本路径
num # 启动线程数,默认 CPU 数 × 2
env
watch
# 监听文件变更路径
name
max_consecutive_failures # 连续失败多少次判定不健康,默认 6
}
}
}
php.ini 的位置按安装方式区分:
- Docker:主配置
/usr/local/etc/php/php.ini(默认不提供,需要自己复制模板),附加目录/usr/local/etc/php/conf.d/*.ini。 - RPM / Debian 包:主配置
/etc/php-zts/php.ini(默认提供生产预设),附加目录/etc/php-zts/conf.d/*.ini。 - 静态二进制:先在执行目录查找 php.ini,其次
/etc/frankenphp/php.ini,附加目录/etc/frankenphp/php.d/*.ini。静态二进制无法加载外部扩展,扩展必须编译进二进制。
自定义镜像里复制模板:
FROM dunglas/frankenphp
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
默认 Caddyfile 模板通过 {$SERVER_NAME:localhost} 支持域名覆盖,{$SERVER_ROOT:public/} 设置站点根目录,默认启用 encode zstd br gzip,预留 Mercure / Vulcain 入口,并通过 import Caddyfile.d/*.caddyfile 加载额外片段。
Worker 模式原理
一个 worker 结构体描述一份 Worker 脚本,可以绑定多个 PHP 线程,每个 Worker 维护独立请求通道、线程池与连续失败计数器。启动时按 Worker 预分配线程,默认是 CPU 核数的 2 倍;请求直接在常驻线程内处理,避免传统 PHP-FPM 每个请求重新初始化整个运行时的开销。热重载由 --watch 触发,文件变更后自动重启相关 Worker 线程。
生态集成
框架集成方面,FrankenPHP 与任何 PHP 应用兼容,为 Laravel、Symfony 提供官方 Worker 模式集成,WordPress 也有集成文档。它可以作为独立 Go 库,把 PHP 嵌入任何基于 net/http 的 Go 应用;也支持创建自执行的独立 PHP 应用。生产部署、性能调优、日志与可观测性另有文档。