FrankenPHP通过Caddy多server块实现单进程托管多站点,每个server块用域名匹配、独立root和php_server配置,共享TLS自动签发与日志,避免多容器端口冲突和证书限速。

可以,但不是靠“容器内起多个 FrankenPHP 进程”,而是靠 Caddy 的多 server 块配置实现单进程托管多个站点。
FrankenPHP 容器本质就是一个 Caddy 实例 + 内置 PHP 运行时
它不像 Nginx 那样只做反向代理,也不像传统 PHP-FPM 那样只管执行——它本身就是个完整 Web 服务器。所以多个站点的路由、TLS、静态文件、PHP 执行,全由同一个 FrankenPHP 进程通过 Caddy 配置分发。
关键点在于:Caddyfile 支持多个 server 块,每个块用 hostname 匹配请求头里的 Host 字段,再各自指定 root、php_server 和证书策略。
- 不需要为每个站点启动新容器或新进程
- 不依赖外部反向代理(比如宿主机再跑一个 Nginx)
- 所有站点共享同一套 TLS 自动签发逻辑(Caddy 默认为每个域名单独申请 Let’s Encrypt 证书)
怎么写 Caddyfile 才能跑两个 Laravel 站点
假设你有两个项目目录:/app/site-a 和 /app/site-b,分别对应 site-a.com 和 site-b.com:
立即学习“PHP免费学习笔记(深入)”;
site-a.com {
root * /app/site-a/public
php_server
encode zstd gzip
}
<p>site-b.com {
root * /app/site-b/public
php_server
encode zstd gzip
}注意几个实操细节:
-
php_server指令必须在每个server块里单独写,不能提上去全局生效 -
root必须精确到public/目录,否则 Laravel 的入口路径会错 - 如果本地测试,用
localhost:8080和localhost:8081无法区分站点,得改 Hosts 或用不同域名(如site-a.test) - Caddy 会为每个域名自动申请证书;若想跳过 HTTPS 强制重定向,加
redir https://{http.request.hostport}{http.request.uri} 301可禁用
挂载多个项目进同一个容器要注意什么
Docker 运行时,-v 参数只能挂载单个目录到 /app,所以不能直接用官方镜像默认路径同时挂两个项目。有三个可行解法:
- 把两个项目都放在宿主机同一父目录下(如
/projects/site-a、/projects/site-b),然后-v /projects:/projects,再在Caddyfile里用绝对路径写root * /projects/site-a/public - 用自定义 Dockerfile 构建镜像,把多个项目 COPY 进镜像内部,避免运行时挂载冲突
- 不挂载源码,改用
git clone或构建时拉取,更适合 CI/CD 场景
容易踩的坑:php_server 默认只处理 .php 后缀,Laravel 的前端控制器依赖 try_files 行为,而 FrankenPHP 的 php_server 已内置等效逻辑——所以别手动加 try_files,否则可能触发双重路由导致 404。
为什么不用多个 FrankenPHP 容器跑多站点
技术上当然可以,但违背了 FrankenPHP 的设计初衷:减少进程数、简化 TLS 管理、统一日志和配置。多个容器意味着:
- 每个容器都要独立监听 443/443/udp 端口,宿主机端口会冲突
- Caddy 的自动 HTTPS 机制在多个容器间无法共享证书缓存,可能触发 Let’s Encrypt 速率限制
- 无法共用同一份访问日志或错误日志做聚合分析
- worker 模式下每个容器都要加载一份框架实例,内存浪费更明显
真正需要隔离的场景(比如不同客户、不同 PHP 版本、不同扩展),才该拆容器;同服务器托管几个内部管理后台或小业务站,单容器多 server 是更轻、更稳的选择。



















