FrankenPHP仅配TCP映射时HTTP/3必然失效,因其底层依赖QUIC(基于UDP),Docker的-p 443:443/tcp不透传UDP包,Caddy收不到QUIC请求;Kubernetes Service原生不支持UDP暴露,需hostNetwork或支持UDP的Ingress解决。

FrankenPHP只配TCP映射,HTTP/3必然失效
HTTP/3 不是 TCP 上的协议升级,它底层完全依赖 QUIC,而 QUIC 必须走 UDP。FrankenPHP 内置 Caddy,只要启用 experimental_http3,Caddy 就会尝试在 HTTPS 端口(默认 :443)上同时监听 TCP 和 UDP;但 Docker 的 -p 443:443/tcp 只透传 TCP 流量,UDP 包被网络层直接丢弃——Caddy 根本收不到 QUIC 连接请求,HTTP/3 静默不可用。
curl --http3 失败的真正原因不是配置没写,而是 UDP 被拦在门外
常见误判:看到 Caddyfile 里写了 experimental_http3,就以为 HTTP/3 已开启。实际上,只要容器没暴露 443/udp,Caddy 启动日志里就不会出现 starting QUIC listener on :443,ss -ulpn | grep ':443' 也查不到任何 UDP 监听行。此时即使用 curl -I https://example.com --http3,返回的也是 curl: (6) Could not resolve host 或 HTTP/3 not supported,本质是客户端发不出第一个 QUIC packet。
Kubernetes Service 无法暴露 UDP,必须靠 Ingress 或 HostNetwork 绕过
Kubernetes 原生 Service 类型(ClusterIP / NodePort / LoadBalancer)不支持 UDP 端口暴露。这意味着:
- 仅靠
Service把443映射到 FrankenPHP Pod,443/udp永远不通 - 云厂商 LoadBalancer(如阿里云 SLB)若未开启「TLS 直通」或「UDP 透传」,443/udp 流量会在 LB 层被丢弃
- 唯一可靠方案是改用
hostNetwork: true+ 宿主机防火墙放行443/udp,或用支持 UDP 的 Ingress Controller(如 Traefik v2.10+)接管
macOS / Windows 上查不到 UDP 占用,不代表它没被系统服务占着
开发环境常遇到:FrankenPHP 启动报 bind: address already in use,但 lsof -i :443 无输出。这是因为:
立即学习“PHP免费学习笔记(深入)”;
-
lsof -i默认不显示 UDP LISTEN 状态,得加-iUDP -sUDP:LISTEN - macOS 上
dns-sd、airportd常静默绑定:443/udp(用于本地 mDNS-SD) - Windows 上某些 Hyper-V 虚拟网卡驱动也会抢占 UDP 443
- 强行 kill 系统进程风险高,更稳妥的做法是换端口(如
--addr :8443)并同步更新 Caddyfile 和安全组



















