frankenphp不支持原生mtls,因其仅实现单向https认证,缺乏ssl_verify_client等双向校验配置项,必须依赖nginx/caddy前置完成tls终止与客户端证书验证,并通过透传请求头(如x-client-dn)供php应用使用。

FrankenPHP 不支持原生 mTLS 配置,必须通过前置 Nginx 或 Caddy 做 TLS 终止并完成客户端证书校验。 它本身是嵌入式 PHP 运行时(基于 SAPI),没有独立的 HTTPS 服务层,所有 TLS 相关逻辑(包括 ssl_verify_client、ssl_client_certificate)都得由反向代理承担。
为什么 FrankenPHP 不能自己配 mTLS
FrankenPHP 启动的是 HTTP/HTTPS 服务,但它的 HTTPS 模式仅支持单向认证:它能加载 server.crt 和 server.key 向客户端证明自己,但不提供任何配置项来要求、验证或读取客户端证书。它的 frankenphp.yaml 中没有类似 Nginx 的 ssl_verify_client 或 Apache 的 SSLVerifyClient 指令。所有 TLS 握手阶段的双向逻辑,它直接交给了底层 libcurl 或系统 OpenSSL,而自身不介入校验环节。
正确做法:用 Nginx 做 mTLS 终止 + FrankenPHP 接纯 HTTP
把 FrankenPHP 当作一个后端应用服务器,所有 TLS 处理(含客户端证书验证)由 Nginx 完成,再以明文 HTTP 转发请求。这是唯一可靠、生产可用的路径:
- Nginx 配置中启用
ssl_verify_client on、指定ssl_client_certificate /path/to/ca.crt、设置ssl_verify_depth 2 - 在
location块里透传身份信息:proxy_set_header X-Client-DN $ssl_client_s_dn和proxy_set_header X-Client-Verify $ssl_client_verify - FrankenPHP 只监听
127.0.0.1:8080这类本地 HTTP 端口,不暴露 HTTPS - 确保 Nginx 的
proxy_pass http://127.0.0.1:8080不带scheme错误(别写成https://)
PHP 应用里怎么拿到客户端身份
FrankenPHP 不会自动把 TLS 层信息注入 $_SERVER,你必须依赖 Nginx 透传的请求头:
- 检查
$_SERVER['HTTP_X_CLIENT_VERIFY'] === 'SUCCESS',否则拒绝请求 - 解析
$_SERVER['HTTP_X_CLIENT_DN'](如CN=payment-service,OU=backend,O=acme)做白名单匹配 - 不要尝试在 PHP 里调用
openssl_x509_parse()解析原始证书——Nginx 没传$ssl_client_cert,且 FrankenPHP 无法访问 TLS 握手上下文 - 若需证书指纹或 SAN 字段,必须让 Nginx 用
proxy_set_header X-Client-Cert $ssl_client_cert(Base64 编码后),PHP 再用base64_decode()解码后解析
容易被忽略的关键点
很多人卡在最后一步:Nginx 透传了头,但 PHP 收不到。这是因为 FrankenPHP 默认不保留原始请求头中的下划线(_)字段——X-Client-DN 会被转成 X-Client-Dn 或直接丢弃。必须在 frankenphp.yaml 的 env 或 server 块中显式启用头传递:
env: { "FRANKENPHP_PRESERVE_HEADERS": "X-Client-DN,X-Client-Verify,X-Client-Cert" }
没加这行,$_SERVER 里就永远看不到这些头。这不是 Nginx 配错,也不是证书问题,而是 FrankenPHP 的默认行为。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











