记一次折磨人的 WebSocket 连接失败排查:宝塔部署环境下 DashScope CosyVoice 的 SSL 证书陷阱
如果你在搜索以下关键词,说明你遇到了同样的问题:
CERTIFICATE_VERIFY_FAILED
websocket connection could not established within 5s
DashScope CosyVoice SSL证书错误
宝塔面板 DashScope 语音合成失败
OpenCloudOS DashScope WebSocket超时
unable to get local issuer certificate
DashScope语音合成SSL配置写在前面
作为开发者,你是否遇到过这样的场景:本地开发环境运行得完美无缺,一旦部署到服务器就各种报错?最近,我就被这样一个问题折磨得夜不能寐——在宝塔面板部署的 Python 服务中,使用 DashScope CosyVoice 合成语音时,WebSocket 连接总是超时失败,而本地测试却完全正常。
经过一整天的排查,终于找到了真凶:一个看似无关紧要的 SSL 证书问题。今天把完整的排查过程和解决方案记录下来,希望能帮助遇到类似问题的朋友节省时间。
问题背景
系统环境
- 部署平台:OpenCloudOS(基于 RHEL),使用宝塔面板管理
- 项目路径:通过宝塔面板自动创建虚拟环境
/www/server/pyporject_evn/dashscope_python311_venv - 服务地址:
dashscope.aliyuncs.com - 涉及组件:DashScope 官方 SDK(
dashscope.audio.tts_v2.SpeechSynthesizer)
故障现象
当通过 Swagger UI 调用语音合成接口时,服务持续返回如下错误:
{
"success": false,
"status": "failed",
"error_message": "调用DashScope语音合成失败,已尝试: mp3@48000 => websocket connection could not established within 5s. Please check your network connection, firewall settings, or server status.; default@default => websocket connection could not established within 5s. Please check your network connection, firewall settings, or server status."
}更令人困惑的是,服务日志中出现了成对的错误信息:
websocket closed due to [SSL: CERTIFICATE_VERIFY_FAILED] unable to get local issuer certificate
TimeoutError: websocket connection could not established within 5s. Please check your network connection, firewall settings, or server status.看到 "CERTIFICATE_VERIFY_FAILED" 这个关键词,我的第一反应是:难道是 DashScope 的 SSL 证书有问题?但转念一想,这不太可能,因为这是阿里云的官方服务。
而且,最关键的问题是:同样的代码和参数,在本地环境完全正常!
这说明问题一定出在服务器环境上。
排查之旅:从绝望到希望的转折
第一步:网络连通性检查
首先,我需要确认服务器能否正常访问 DashScope 的服务。
# 测试 TCP 连接
nc -zv dashscope.aliyuncs.com 443结果是成功的,端口 443 可以连通。
# 测试 HTTP 连接
curl --http1.1 -i -N https://dashscope.aliyuncs.com/compatible-mode/v1/models也能正常返回 HTTP 101 Switching Protocols,说明网络和防火墙都不是问题。
初步结论:网络层面没有问题。
第二步:真实 WebSocket 测试
为了排除代码层面问题,我在宿主机上直接运行了一个 Python 脚本,模拟 DashScope SDK 的调用:
import json
import uuid
import websocket
ws = websocket.create_connection(
"wss://dashscope.aliyuncs.com/api-ws/v1/inference",
timeout=10
)
ws.send(json.dumps({
"task_id": str(uuid.uuid4()),
"voice": "YOUR_VOICE_ID",
"format": "mp3",
"text": "测试"
}))
result = ws.recv()
print(f"收到响应: {result}")
ws.close()结果令人惊讶:在宿主机上,脚本能够顺利收到 task-started 响应!这表明:
- DashScope 服务本身没有问题
- API Key 配置正确
- WebSocket 连接机制本身是正常的
关键发现:问题只存在于虚拟环境的 Python 进程中。
第三步:SSL 证书问题浮现
回到服务日志,我注意到这一行关键信息:
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate这提示我:SSL 证书验证失败!
我立刻联想到了什么。宝塔面板创建的虚拟环境,可能默认没有加载系统级的 CA 证书。这在企业内网环境或某些发行版中很常见。
让我验证一下证书情况:
python3 -c "import certifi; print(certifi.where())"输出:
/www/server/pyporject_evn/dashscope_python311_venv/lib/python3.11/site-packages/certifi/cacert.pem找到了!虚拟环境中确实有 certifi 包,但问题在于:Python 进程在启动时,没有正确加载 certifi 的根证书。
第四步:解决方案验证
现在我需要在宝塔面板的 Python 项目配置中添加 SSL 证书相关的环境变量。
在宝塔面板中按以下步骤操作:
- 登录宝塔面板
- 找到您的 Python 项目,点击"设置"
- 点击"环境变量"选项卡
- 点击"添加环境变量"按钮
- 分别添加以下两个环境变量:

添加的环境变量:
# 第一个环境变量
名称:SSL_CERT_FILE
值:/www/server/pyporject_evn/dashscope_python311_venv/lib/python3.11/site-packages/certifi/cacert.pem
# 第二个环境变量
名称:REQUESTS_CA_BUNDLE
值:/www/server/pyporject_evn/dashscope_python311_venv/lib/python3.11/site-packages/certifi/cacert.pem保存配置后,重启整个 Python 项目。
第五步:验证结果
重启服务后,我再次通过 Swagger 调用语音合成接口。
成功了!
任务状态顺利从 pending → task-started → task-finished,result_audio_url 正常返回,服务日志中也不再出现任何 SSL 错误信息,只有正常的调用记录。
深入分析:为什么会这样?
问题的本质
这次问题的根本原因是:宝塔面板创建的 Python 虚拟环境默认没有正确加载系统级的 CA 证书,这导致 TLS 握手过程中无法验证 DashScope 的 SSL 证书。
具体来说:
- 宝塔的虚拟环境使用
certifi包管理证书 - 但 Python 进程启动时,如果没有显式指定
SSL_CERT_FILE或REQUESTS_CA_BUNDLE环境变量,就会使用系统默认的证书路径 - 在 OpenCloudOS(RHEL 系)系统中,虚拟环境下这些环境变量可能为空或指向错误位置
- 结果就是 Python 的
ssl模块无法验证服务器证书,导致 WebSocket 连接在 SSL 握手阶段就失败
为什么本地环境正常?
本地开发环境(通常是 Ubuntu/macOS/Windows)的 Python 环境通常有以下特点:
- 操作系统级别安装了完整的 CA 证书包
- Python 的
certifi能够自动找到系统证书位置 - 或者直接在
/etc/ssl/certs/目录提供了证书文件
所以本地环境不会遇到这个问题。
最佳实践与预防措施
1. 部署前检查清单
在将应用部署到服务器环境之前,建议执行以下检查:
# 检查证书环境变量
python3 -c "import certifi, os; print('Certifi路径:', certifi.where()); print('SSL_CERT_FILE:', os.environ.get('SSL_CERT_FILE')); print('REQUESTS_CA_BUNDLE:', os.environ.get('REQUESTS_CA_BUNDLE'))"
# 测试 HTTPS 连接
curl -v https://dashscope.aliyuncs.com/compatible-mode/v1/models 2>&1 | head -20
# 测试 WebSocket 连接
python3 <<'PY'
import websocket
try:
ws = websocket.create_connection("wss://dashscope.aliyuncs.com/api-ws/v1/inference", timeout=5)
print("WebSocket连接成功")
ws.close()
except Exception as e:
print(f"WebSocket连接失败: {e}")
PY2. 推荐的配置方案
优先级说明:根据不同的部署环境,推荐方案的优先级如下:
- 宝塔面板部署:首选方案一(最快捷)
- 传统服务器部署:首选方案二或方案三
- systemd 服务部署:使用方案四
方案一:宝塔面板环境变量配置(最快捷,推荐!)
如果您的项目部署在宝塔面板中,这是最简单直接的解决方案:
操作步骤:
- 登录宝塔面板
- 找到您的 Python 项目,点击"设置"
- 点击"环境变量"选项卡
- 点击"添加环境变量"按钮
- 添加以下两个环境变量:
# 第一个环境变量
名称:SSL_CERT_FILE
值:/www/server/pyporject_evn/dashscope_python311_venv/lib/python3.11/site-packages/certifi/cacert.pem
# 第二个环境变量
名称:REQUESTS_CA_BUNDLE
值:/www/server/pyporject_evn/dashscope_python311_venv/lib/python3.11/site-packages/certifi/cacert.pem注意事项:
- 路径中的
dashscope_python311_venv需要替换为您实际的虚拟环境名称 - 或者使用动态获取路径:
$(python -m certifi) - 设置完成后需要重启项目使环境变量生效
方案二:在项目启动脚本中设置
在项目的启动脚本(如 start.sh)中显式设置环境变量:
#!/bin/bash
# start.sh
# 设置 SSL 证书环境变量
export SSL_CERT_FILE=$(python -m certifi)
export REQUESTS_CA_BUNDLE=$(python -m certifi)
# 启动服务
cd /path/to/your/project
python app/main.py这样可以确保每次启动时都使用正确的证书路径。
方案三:在虚拟环境的激活脚本中设置
如果使用虚拟环境,可以在 venv/bin/activate 文件末尾添加:
# 在虚拟环境激活时设置证书环境变量
export SSL_CERT_FILE=$(python -m certifi)
export REQUESTS_CA_BUNDLE=$(python -m certifi)方案四:在 systemd 服务文件中设置
如果服务通过 systemd 管理,可以在服务文件中添加:
[Service]
Environment=SSL_CERT_FILE=/path/to/venv/lib/python3.x/site-packages/certifi/cacert.pem
Environment=REQUESTS_CA_BUNDLE=/path/to/venv/lib/python3.x/site-packages/certifi/cacert.pem3. 通用排查流程
遇到类似问题时,可以遵循以下排查流程:
检查网络连通性
ping dashscope.aliyuncs.com nc -zv dashscope.aliyuncs.com 443检查 SSL 证书状态
openssl s_client -connect dashscope.aliyuncs.com:443 -servername dashscope.aliyuncs.com < /dev/null检查 Python 环境变量
python -c "import os; print({k:v for k,v in os.environ.items() if 'CERT' in k or 'SSL' in k})"检查 certifi 包
python -c "import certifi; print('Certifi 版本:', certifi.__version__); print('证书路径:', certifi.where())"在真实环境中测试 WebSocket
- 不要在宿主机测试,要在虚拟环境的 Python 进程中测试
- 使用与生产代码相同的调用方式
4. 容器化部署的注意事项
如果使用 Docker 等容器化部署,建议在 Dockerfile 中添加:
# 安装 CA 证书包(Ubuntu/Debian)
RUN apt-get update && apt-get install -y ca-certificates
# 或(CentOS/RHEL)
RUN yum install -y ca-certificates
# 设置环境变量
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt5. 监控与告警
在生产环境中,建议:
- 监控 SSL 证书相关错误日志
- 定期检查证书到期时间
- 添加 WebSocket 连接失败的告警
总结与思考
这次排查经历让我深刻体会到:
- 本地与生产环境的差异性:看似相同的代码,在不同环境下可能表现完全不同
- 日志分析的重要性:仔细阅读服务日志往往能找到关键线索(
CERTIFICATE_VERIFY_FAILED) - 环境隔离的副作用:虚拟环境虽然隔离了依赖,但可能隐藏了系统级配置问题
- 网络层不是万能的:TCP 连通不代表 TLS 握手成功
对于经常使用第三方云服务的项目,建议:
- 建立标准化的部署流程,包含环境变量检查
- 编写自动化测试脚本,在目标环境中验证关键依赖
- 积累常见问题的排查经验,形成文档化知识库
最后,希望这篇文章能帮助遇到类似问题的开发者快速定位问题,不再为这类"环境问题"浪费宝贵的时间。
推荐验证清单:
- [ ]
nc dashscope.aliyuncs.com 443- 检查 TCP 连通性 - [ ]
curl --http1.1 ...- 检查 HTTP→WebSocket 握手 - [ ] Python WebSocket 脚本 - 在目标环境模拟真实调用
- [ ] 查看服务日志 - 确认仍有
CERTIFICATE_VERIFY_FAILED错误 - [ ] 检查 certifi 路径和环境变量 - 确保指向正确位置
通过上述步骤,即可快速定位并解决 DashScope CosyVoice 在服务器端"5 秒握手超时"的问题。
快速导航:相关搜索关键词
核心错误:
CERTIFICATE_VERIFY_FAILEDwebsocket connection could not established within 5sunable to get local issuer certificateTimeoutError: websocket connection could not established
服务/平台:
DashScope CosyVoice阿里云 DashScope宝塔面板OpenCloudOSRHEL 系统
解决方案:
SSL_CERT_FILE 环境变量REQUESTS_CA_BUNDLE 环境变量certifi cacert.pemPython 虚拟环境 SSL 配置宝塔 Python 项目 SSL 证书
问题现象:
本地正常服务器失败WebSocket 握手超时宝塔部署 DashScope 语音合成失败OpenCloudOS SSL 证书问题
如果您通过以上任何关键词搜索到本文,说明问题相似,请重点关注 "SSL_CERT_FILE" 和 "REQUESTS_CA_BUNDLE" 两个环境变量的配置。