workerman https启动报err_ssl_protocol_error,主因是未启用tls握手:需确认php已加载openssl扩展,证书为pem格式且local_cert含私钥+域名证书+中间证书三者拼接,ssl_context必须构造时传入而非set设置,verify_peer必须为false。

Workerman 4.0.34 启动 HTTPS 服务时,浏览器访问直接报 ERR_SSL_PROTOCOL_ERROR,不是证书无效,而是 Workerman 根本没启用 TLS 握手——它在监听 443 端口的同时仍跑着裸 TCP,协议栈压根没加载 SSL 层。
确认 PHP 环境支持 OpenSSL
执行 php -m | grep openssl,输出必须含 openssl。若无输出,需重新编译 PHP 并启用 --with-openssl 参数,或在 Ubuntu 上运行 sudo apt install php-opcache php-curl php-xml php-mbstring php-zip php-gd php-bcmath php-redis(其中 php-opcache 会自动拉入 openssl 依赖)。
这一步跳过会导致后续所有配置成功但服务启动即失败,错误日志里只显示 “failed to listen”,不提 SSL。
准备 PEM 格式证书链
证书必须是 PEM 格式,且 【local_cert 必须包含私钥 + 域名证书 + 中间证书三者按序拼接】。用 Let’s Encrypt 的话,直接取 fullchain.pem(不是 cert.pem),私钥用 privkey.pem。
验证命令:openssl x509 -in fullchain.pem -text -noout | head -10 应看到 “Certificate” 开头;openssl rsa -in privkey.pem -check -noout 返回 “RSA key ok” 才算有效。
别把 PFX 或 DER 文件直接丢进去——Workerman 会静默报错 failed to load certificate,连启动都卡住。
Workerman 4.0.34 正确配置 ssl_context
使用 Workerman\Protocols\Http\WebServer 类启动 HTTPS 服务,【ssl_context 必须作为构造参数传入,不能靠 set 方法后期补】。
方法一:完整数组写法(推荐)
第一步:$context = ['ssl' => ['local_cert' => '/var/www/myapp/certs/fullchain.pem', 'local_pk' => '/var/www/myapp/certs/privkey.pem', 'verify_peer' => false]];
第二步:$web = new WebServer('ssl://0.0.0.0:443', $context);
第三步:$web->onMessage = function ($connection, $request) { $connection->send('<h1>HTTPS OK</h1>'); };
注意:路径必须是绝对路径,__DIR__ . '/certs/fullchain.pem' 可防工作目录变化导致文件找不到;verify_peer => false 是强制项,设为 true 会导致小程序或浏览器握手失败。
方法二:单行路径写法(仅限开发测试)
$web = new WebServer('ssl://0.0.0.0:443/fullchain.pem:/privkey.pem');
该写法省略数组,但要求两个文件在同一目录、权限一致、且不能加密码;生产环境禁用,因无法设置 verify_peer,上线后会因校验失败断连。
绕过 Nginx 直连 Workerman 的关键检查项
若你坚持让 Workerman 自己扛 HTTPS(而非用 Nginx 反代),请逐项核对:
确保防火墙放行目标端口(如 443 或 8443),sudo ufw status 查看规则,sudo ufw allow 443 补开;
域名必须已备案且解析到服务器公网 IP,dig your-domain.com +short 输出应为真实 IP;
PHP 进程用户(如 www-data)对证书文件有读权限:sudo chown www-data:www-data /var/www/myapp/certs/*.pem && sudo chmod 600 /var/www/myapp/certs/*.pem;
【不要同时开启 Nginx SSL 和 Workerman SSL】,否则 wss 连接会因双重加密 handshake failure 而重置。











