使用Workerman搭建WebSocket遇自签SSL连接失败问题求助
解决Workerman WebSocket(WSS)与Apache共存的连接问题
核心问题分析
- 端口冲突:80/443是Apache默认的HTTP/HTTPS端口,Workerman无法同时监听这些端口,导致连接请求被Apache拦截而非转发到Workerman服务。
- WSS配置缺失:Workerman默认的
websocket://协议不支持SSL加密,直接用wss://发起连接会因协议不匹配失败。 - 浏览器端口默认行为:使用
wss://127.0.0.1:443时,浏览器会自动忽略443端口(WSS默认端口),但此时443被Apache占用,连接仍指向Apache而非Workerman。
解决方案
方案1:Workerman直接配置SSL,使用非标准端口
- 修改Workerman代码,添加SSL上下文,指定非标准端口(如8080):
// 替换为你的自签名证书和私钥路径 $sslContext = [ 'ssl' => [ 'local_cert' => '/var/www/html/ssl/cert.pem', 'local_pk' => '/var/www/html/ssl/private.key', 'verify_peer' => false, ] ]; // 使用wss协议监听8080端口 $worker = new Worker('wss://127.0.0.1:8080', $sslContext); $worker->onMessage = function($connection, $data) use($worker) { foreach($worker->connections as $clientConnection) { $clientConnection->send('Hello World'); } }; Worker::runAll();
- 前端连接代码同步修改:
let socket = new WebSocket('wss://127.0.0.1:8080');
- 确保防火墙开放8080端口,若用非root用户启动Workerman,需通过
sudo或调整端口权限避免监听失败。
方案2:Apache反向代理(推荐,共用443端口)
利用Apache作为中间层,将WSS请求转发给Workerman服务,无需修改端口:
- 修改Workerman监听本地非标准端口(不启用SSL):
$worker = new Worker('websocket://127.0.0.1:8080'); $worker->onMessage = function($connection, $data) use($worker) { foreach($worker->connections as $clientConnection) { $clientConnection->send('Hello World'); } }; Worker::runAll();
- 在Apache站点配置文件(如
/etc/apache2/sites-available/localhost.conf)中添加反向代理规则:
<VirtualHost *:443> # 原有SSL配置 SSLEngine on SSLCertificateFile /path/to/your/cert.pem SSLCertificateKeyFile /path/to/your/private.key # 反向代理WSS请求到Workerman ProxyPass /ws ws://127.0.0.1:8080/ ProxyPassReverse /ws ws://127.0.0.1:8080/ # 原有站点配置 DocumentRoot /var/www/html ServerName localhost </VirtualHost>
- 启用Apache代理相关模块并重启服务:
sudo a2enmod proxy proxy_http proxy_wstunnel sudo systemctl restart apache2
- 前端连接代码修改为:
let socket = new WebSocket('wss://localhost/ws');
额外注意事项
- 自签名证书需在浏览器中手动添加信任,否则WSS连接可能被拦截。
- 启动Workerman前,用
sudo lsof -i :8080检查端口是否被占用。 - 非root用户无法监听1024以下端口,若需使用低端口需通过
sudo启动Workerman。
内容的提问来源于stack exchange,提问作者Sandro Sandro
相关产品推荐
相关产品推荐

