必须在每个启用 HTTPS 的 server 块内配置 ssl_protocols TLSv1.2 TLSv1.3;,禁用 SSLv2/SSLv3/TLSv1.0/TLSv1.1;该指令在 http 或 location 块中无效,且需配合强加密套件与实测验证。

直接在 FrankenPHP 的 Nginx 配置(或 Caddy、Apache 等反代层)中禁用 TLS 1.2 以下协议——FrankenPHP 本身不处理 TLS 协商,它只接收已建立的 HTTP 连接。所以“禁用老客户端”这件事,必须在前置 Web 服务器上做。
FrankenPHP 不解析 TLS,只跑 PHP
FrankenPHP 是一个嵌入式 PHP 运行时,通常以php-fpm 替代品身份部署在 Nginx / Caddy / Apache 后面。它不监听 443 端口,也不参与 SSL/TLS 握手。所有协议版本控制、证书加载、加密套件协商,都由前端 Web 服务器完成。你看到的“客户端不支持协议”错误,永远来自 Nginx(或 Caddy)的 TLS 层,而非 FrankenPHP。
在 Nginx 中精准禁用 TLS 1.0/1.1
如果你用 Nginx 做反代(最常见场景),就在每个启用 HTTPS 的server 块里加这行:
ssl_protocols TLSv1.2 TLSv1.3;
- 必须放在 server { ... } 内部,不能写在 http 或 location 块里
- 每个 listen 443 ssl 的 server 都要单独写,漏一个就等于留后门
- 禁止出现 TLSv1、TLSv1.1、TLSv1.0 字样,哪怕只是多一个空格或少一个分号都会导致配置失效
光禁协议不够,还得锁死加密套件
立即学习“PHP免费学习笔记(深入)”;
旧协议禁了,但若仍允许AES128-SHA、ECDHE-RSA-RC4-SHA 这类弱套件,TLS 1.2 连接照样能被降级攻击或暴力破解。
- 显式指定强套件:ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
- 关闭客户端优先:ssl_prefer_server_ciphers on;
- 确保不包含 RC4、MD5、SHA1、DES、3DES 字样
验证是否真生效,别信 reload 就完事
nginx -t && nginx -s reload 只校验语法,不验证行为。必须实测:
- 测试 TLS 1.1 是否被拒:openssl s_client -connect your-domain.com:443 -tls1_1 -servername your-domain.com → 应返回 handshake failed 或连接超时
- 测试 TLS 1.2 是否通:openssl s_client -connect your-domain.com:443 -tls1_2 -servername your-domain.com → 输出中要有 Protocol : TLSv1.2
- 用 nmap --script ssl-enum-ciphers -p 443 your-domain.com 查看完整支持列表,确认无 TLSv1.0/TLSv1.1 区块
FrankenPHP 自身没有 TLS 控制能力,所有安全边界都在它前面那层 Web 服务器里。最容易被忽略的是:多个虚拟主机配置文件分散在 /etc/nginx/sites-enabled/ 下,改了一个却忘了另一个;或者域名 DNS 指向了另一台未更新的 Nginx 机器——这时候扫描工具报 TLS 1.1,你却在 FrankenPHP 日志里翻半天。



















