PHP实现Secure Websockets(WSS) 如何为脚本配置SSL证书
问题解答
核心概念澄清
- PHP的
socket_*系列函数和stream_*系列函数是两套独立的底层实现,你无法直接为socket_create()创建的socket资源配置SSL证书,这就是你之前尝试失败的根本原因。 - 要实现wss协议,你有两个可选方案:一是改用支持SSL上下文的
stream_socket_*系列函数重构服务端监听逻辑,二是用Nginx等反向代理做SSL卸载,不需要修改原有websocket服务代码。
方案一:重构代码适配SSL(直接实现wss)
第一步:修正SSL上下文配置
你原来的配置用了http字段,实际应该用ssl字段:
$opts = [ 'ssl' => [ 'local_cert' => '/usr/local/etc/apache224/ssl.crt/www.mojehra.cz.crt', 'local_pk' => '/usr/local/etc/apache224/ssl.key/www.mojehra.cz.key', 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true // 自签证书需要开启,正规CA证书可关闭 ] ]; $context = stream_context_create($opts);
第二步:替换原有socket监听逻辑
把原来的socket_create、socket_bind、socket_listen替换为stream_socket_server:
// 替换原有socket创建逻辑 $socketResource = stream_socket_server( "ssl://0.0.0.0:".PORT, $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context ); if (!$socketResource) die("服务启动失败: $errstr ($errno)");
第三步:修改后续IO操作相关函数
把所有socket_*对应的操作替换为stream相关函数:
socket_accept→stream_socket_acceptsocket_read→freadsocket_write→fwritesocket_recv→freadsocket_select→stream_selectsocket_close→fclose
第四步:修改ChatHandler的握手逻辑
把doHandshake方法里的ws地址改为wss:
// 把原来的ws://改为wss:// "WebSocket-Location: wss://$host_name:$port/demo/shout.php\r\n".
方案二:Nginx反向代理SSL卸载(推荐,无需修改原代码)
这个方案不需要改动你现有的websocket服务代码,用Nginx做SSL层转发即可,配置示例:
server { listen 8090 ssl; server_name 你的实际域名; ssl_certificate /usr/local/etc/apache224/ssl.crt/www.mojehra.cz.crt; ssl_certificate_key /usr/local/etc/apache224/ssl.key/www.mojehra.cz.key; location /ws { proxy_pass http://127.0.0.1:8089; # 你原来的websocket服务监听本地8089端口即可 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } }
用户端直接连接wss://你的域名:8090/ws即可,原有服务不需要做任何修改。
注意事项
- 确保你的PHP已开启openssl扩展
- 证书路径必须是绝对路径,且PHP进程有读取权限
- 对应端口需开放防火墙规则
内容的提问来源于stack exchange,提问作者Láďa
相关产品推荐
相关产品推荐

