frankenphp两个实例共用默认管理端口:2019会导致后启动实例bind失败退出,因其不自动fallback或提示可用端口;需通过--admin-addr参数或frankenphp.yaml中admin_addr字段为各实例显式指定互不重叠的管理端口。

FrankenPHP 两个实例不能共用同一个管理端口(默认 :2019),否则后启动的会因 bind 失败直接退出——它不自动 fallback,也不提示可用端口。
为什么管理端口会冲突
FrankenPHP 的管理接口(用于健康检查、metrics、pprof 等)默认监听 127.0.0.1:2019,且该端口与 HTTP 服务端口(如 :8000)完全独立。即使你把两个实例的 HTTP 端口设成 :8000 和 :8001,只要没显式改管理端口,它们仍会同时尝试绑定 :2019,导致第二个实例启动失败。
- 错误现象:
listen tcp 127.0.0.1:2019: bind: address already in use - 常见误判:以为只改了
--addr就够了,其实管理端口需单独配置 - Windows/macOS/Linux 行为一致,无平台差异
如何显式指定不同管理端口
FrankenPHP 通过 --admin-addr 参数控制管理接口绑定地址,必须为每个实例单独设置且互不重叠。
- 实例 A 启动命令:
frankenphp php-server --addr :8000 --admin-addr :2019 - 实例 B 启动命令:
frankenphp php-server --addr :8001 --admin-addr :2020 - 若跑在 Docker 中,还需映射对应端口:
-p 2020:2020,并确保容器内防火墙或 SELinux 不拦截 - 配置文件方式(
frankenphp.yaml):在server下加admin_addr: ":2020"字段
验证管理端口是否真被占用
别只看启动日志,要主动确认端口归属。不同系统命令不同,但目标一致:查 :2019 类端口是否已被监听,且进程名是 frankenphp。
- macOS/Linux:
lsof -P -n -i :2019或sudo lsof -iTCP -sTCP:LISTEN | grep :2019 - Windows(管理员 CMD):
netstat -ano | findstr :2019,再用tasklist /FI "PID eq 1234"查进程名 - 看到多个
frankenphp占着不同管理端口?说明配置生效;若只有一个:2019被占而另一个报错,就是漏配--admin-addr
容易忽略的细节
管理端口冲突不像 HTTP 端口那样直观——它不阻断请求,但会让 Prometheus 抓不到 metrics、/healthz 返回 500、pprof 无法调试。而且 FrankenPHP 不会在启动日志里强调“管理端口已启用”,只在 debug 日志中提一句 admin server listening on 127.0.0.1:2019,多数人根本不会开 debug 模式。
- 如果你用 systemd 或 supervisord 管理多个 FrankenPHP 实例,
ExecStart或 command 配置里必须包含--admin-addr - 环境变量方式(如
FRANKENPHP_ADMIN_ADDR=:2020)也有效,但优先级低于命令行参数 - 别把管理端口暴露到公网——它没有认证机制,
/debug/pprof可被任意读取
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











