frankenphp 不涉及证书链问题,因为它仅作为 php 运行时嵌入应用,不监听端口、不参与 tls 握手、不发送证书;https 终止由前端 nginx 或 caddy 完成,证书链完整性完全取决于其 ssl_certificate 是否配置为包含域名证书与中间证书的 fullchain.pem 文件。

FrankenPHP 本身不处理证书链下发,它只是 PHP 运行时,SSL 终止由前端 Web 服务器(如 Nginx 或 Caddy)完成;浏览器报错“证书不可信”“NET::ERR_CERT_AUTHORITY_INVALID”,问题一定出在 Nginx/Caddy 的 TLS 配置上,而非 FrankenPHP。
为什么 FrankenPHP 不涉及证书链问题
FrankenPHP 是以 SAPI 方式嵌入 PHP 的运行时,它不监听 443 端口、不参与 TLS 握手、不发送任何证书。所有 HTTPS 流量必须先经过反向代理(典型是 Nginx),由它完成 SSL 终止后,再以 HTTP/HTTPS 转发给 FrankenPHP 的 PHP 应用(如通过 fastcgi_pass 或 proxy_pass)。所以证书链是否完整,完全取决于 Nginx 的 ssl_certificate 配置是否包含中间证书。
Nginx 配置中 ssl_certificate 必须指向 fullchain.pem
常见错误是只把域名证书(domain.crt)设为 ssl_certificate 值,导致 Nginx 只发送这一张证书,浏览器无法向上验证。正确做法是合并:
- 把你的域名证书内容(
-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----)放在最前面 - 紧接着换一行,粘贴中间证书(CA Bundle,来自 Let’s Encrypt 的
fullchain.pem或 Sectigo/DigiCert 提供的ca-bundle.crt) - 保存为
/etc/nginx/ssl/fullchain.pem(路径可自定,但需确保权限为644) - 在 Nginx server 块中写:
ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/domain.key;
验证证书链是否真的发给了浏览器
别信宝塔面板的“证书链检测”或 Nginx -t 成功——要实测 Nginx 是否真把中间证书发出去:
- 在服务器执行:
openssl s_client -connect your-domain.com:443 -servername your-domain.com -showcerts 2>/dev/null | grep "BEGIN CERTIFICATE" | wc -l,输出应 ≥ 2 - 在 Chrome 访问该域名 → 点锁图标 → “连接是安全的” → “证书有效” → “证书路径”,应看到两层或三层(域名证书 → 中间证书 → 根证书)
- 安卓设备尤其敏感,若 iOS 正常而安卓白屏或报错,基本可锁定为链不完整
别误用 ssl_trusted_certificate 试图“修复”服务端链
ssl_trusted_certificate 在 Nginx 中仅用于两种场景:
- 启用双向 TLS(
ssl_verify_client on)时,指定可信客户端 CA 列表 - 配合
proxy_ssl_verify on验证上游服务(比如 FrankenPHP 后面还套了另一个 HTTPS 服务)
它**不会补全你自己的证书链**,也不会影响浏览器对你站点的校验。把它设成和 ssl_certificate 一样的文件,纯属冗余,且容易让人误以为“配了就完了”。
真正容易被忽略的是:FrankenPHP 用户常直接用 Caddy 或 Nginx 的快速配置模板,这些模板默认没检查证书文件内容,一旦上传的 PEM 文件里只有域名证书,问题就静默存在——直到某天安卓用户打不开页面才暴露出来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











