frankenphp无法按域名单独禁用http/3,因其不参与协议协商;http/3由caddy全局控制,依赖udp端口与alpn机制,quic连接面向ip:port而非域名,故不支持per-host开关。

FrankenPHP 无法按域名单独禁用 HTTP/3
不能。HTTP/3 的启用是全局协议层行为,由 Caddy 的 servers 块控制,FrankenPHP 本身不参与 HTTP 协议协商,只处理 PHP 请求生命周期。Caddy 不支持 per-host(每个域名)开关 HTTP/3 —— 一旦在 servers 中启用了 experimental_http3,所有监听该 server 的域名都会走 HTTP/3(前提是客户端支持且 TLS 配置合规)。
Caddy 的 HTTP/3 开关位置和生效范围
必须写在 Caddyfile 的全局配置块(即最顶部的 { } 内),例如:
{ servers { protocol { experimental_http3 } } frankenphp { num_threads auto } }
这个配置影响整个 Caddy 实例的所有 HTTPS server,与后续的 example.com { ... } 块无关。你无法在某个域名块里加 http3 off 或类似指令来覆盖它。
- 尝试在域名块内写
protocol { experimental_http3 }会报错:Caddy 不允许嵌套重复协议配置 - 删掉全局
experimental_http3,所有域名都退回到 HTTP/2 - 想让某域名“看起来没开 HTTP/3”,唯一办法是让它不走 HTTPS(比如只监听 :80),但这样实际已脱离 HTTP/3 前提(HTTP/3 必须基于 QUIC + TLS 1.3)
为什么不能按域名区分?底层限制在哪
HTTP/3 是传输层协议扩展,依赖 UDP 端口(默认 443)和 ALPN 协商机制。Caddy 在启动时为每个 servers 实例绑定一次 UDP listener,并统一注册 ALPN token h3。它不为不同 Host 头维护独立的 QUIC stack 实例 —— 这不是 FrankenPHP 的限制,而是 Caddy 架构和 QUIC 协议本身的约束。
- ALPN 是 TLS 握手阶段协商的,发生在 Host 头解析之前
- QUIC connection 是面向 IP:port 的,不是面向域名的
- FrankenPHP 完全不接触 ALPN 或 UDP 层,它只接收 Caddy 已解密并解析完的 HTTP 请求(无论来自 HTTP/1.1、HTTP/2 还是 HTTP/3)
替代方案:用不同端口或不同 Caddy 实例隔离
如果业务上真有“部分域名禁 HTTP/3”的强需求(比如兼容老旧监控工具只认 HTTP/2 的 ALPN),只能靠部署层面绕过:
- 为需禁用 HTTP/3 的域名单独起一个 Caddy 实例,监听不同端口(如 :4443),且不开启
experimental_http3 - 前端加反向代理(如 Nginx),对目标域名终止 QUIC,降级转发为 HTTP/2 到后端 Caddy+FrankenPHP
- 直接改用传统 Apache/Nginx + PHP-FPM,它们本就不原生支持 HTTP/3,天然规避该问题
注意:这些都不是 FrankenPHP 的配置选项,而是架构妥协。真实生产环境极少需要这种粒度的协议隔离 —— 更常见的问题是验证 alt-svc 头是否被正确下发,或排查客户端因 UDP 阻塞导致的 HTTP/3 回退。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











