如果你在搜索以下关键词,说明你遇到了同样的问题

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 响应!这表明:

  1. DashScope 服务本身没有问题
  2. API Key 配置正确
  3. 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 证书相关的环境变量。

在宝塔面板中按以下步骤操作:

  1. 登录宝塔面板
  2. 找到您的 Python 项目,点击"设置"
  3. 点击"环境变量"选项卡
  4. 点击"添加环境变量"按钮
  5. 分别添加以下两个环境变量:

2025-11-25T02:27:59.png

添加的环境变量

# 第一个环境变量
名称: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 调用语音合成接口。

成功了!

任务状态顺利从 pendingtask-startedtask-finishedresult_audio_url 正常返回,服务日志中也不再出现任何 SSL 错误信息,只有正常的调用记录。

深入分析:为什么会这样?

问题的本质

这次问题的根本原因是:宝塔面板创建的 Python 虚拟环境默认没有正确加载系统级的 CA 证书,这导致 TLS 握手过程中无法验证 DashScope 的 SSL 证书。

具体来说:

  1. 宝塔的虚拟环境使用 certifi 包管理证书
  2. 但 Python 进程启动时,如果没有显式指定 SSL_CERT_FILEREQUESTS_CA_BUNDLE 环境变量,就会使用系统默认的证书路径
  3. 在 OpenCloudOS(RHEL 系)系统中,虚拟环境下这些环境变量可能为空或指向错误位置
  4. 结果就是 Python 的 ssl 模块无法验证服务器证书,导致 WebSocket 连接在 SSL 握手阶段就失败

为什么本地环境正常?

本地开发环境(通常是 Ubuntu/macOS/Windows)的 Python 环境通常有以下特点:

  1. 操作系统级别安装了完整的 CA 证书包
  2. Python 的 certifi 能够自动找到系统证书位置
  3. 或者直接在 /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}")
PY

2. 推荐的配置方案

优先级说明:根据不同的部署环境,推荐方案的优先级如下:

  • 宝塔面板部署:首选方案一(最快捷)
  • 传统服务器部署:首选方案二或方案三
  • systemd 服务部署:使用方案四

方案一:宝塔面板环境变量配置(最快捷,推荐!)

如果您的项目部署在宝塔面板中,这是最简单直接的解决方案:
2025-11-25T02:28:17.png
操作步骤

  1. 登录宝塔面板
  2. 找到您的 Python 项目,点击"设置"
  3. 点击"环境变量"选项卡
  4. 点击"添加环境变量"按钮
  5. 添加以下两个环境变量:
# 第一个环境变量
名称: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.pem

3. 通用排查流程

遇到类似问题时,可以遵循以下排查流程:

  1. 检查网络连通性

    ping dashscope.aliyuncs.com
    nc -zv dashscope.aliyuncs.com 443
  2. 检查 SSL 证书状态

    openssl s_client -connect dashscope.aliyuncs.com:443 -servername dashscope.aliyuncs.com < /dev/null
  3. 检查 Python 环境变量

    python -c "import os; print({k:v for k,v in os.environ.items() if 'CERT' in k or 'SSL' in k})"
  4. 检查 certifi 包

    python -c "import certifi; print('Certifi 版本:', certifi.__version__); print('证书路径:', certifi.where())"
  5. 在真实环境中测试 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.crt

5. 监控与告警

在生产环境中,建议:

  1. 监控 SSL 证书相关错误日志
  2. 定期检查证书到期时间
  3. 添加 WebSocket 连接失败的告警

总结与思考

这次排查经历让我深刻体会到:

  1. 本地与生产环境的差异性:看似相同的代码,在不同环境下可能表现完全不同
  2. 日志分析的重要性:仔细阅读服务日志往往能找到关键线索(CERTIFICATE_VERIFY_FAILED
  3. 环境隔离的副作用:虚拟环境虽然隔离了依赖,但可能隐藏了系统级配置问题
  4. 网络层不是万能的:TCP 连通不代表 TLS 握手成功

对于经常使用第三方云服务的项目,建议:

  • 建立标准化的部署流程,包含环境变量检查
  • 编写自动化测试脚本,在目标环境中验证关键依赖
  • 积累常见问题的排查经验,形成文档化知识库

最后,希望这篇文章能帮助遇到类似问题的开发者快速定位问题,不再为这类"环境问题"浪费宝贵的时间。


推荐验证清单

  • [ ] nc dashscope.aliyuncs.com 443 - 检查 TCP 连通性
  • [ ] curl --http1.1 ... - 检查 HTTP→WebSocket 握手
  • [ ] Python WebSocket 脚本 - 在目标环境模拟真实调用
  • [ ] 查看服务日志 - 确认仍有 CERTIFICATE_VERIFY_FAILED 错误
  • [ ] 检查 certifi 路径和环境变量 - 确保指向正确位置

通过上述步骤,即可快速定位并解决 DashScope CosyVoice 在服务器端"5 秒握手超时"的问题。


快速导航:相关搜索关键词

核心错误

  • CERTIFICATE_VERIFY_FAILED
  • websocket connection could not established within 5s
  • unable to get local issuer certificate
  • TimeoutError: websocket connection could not established

服务/平台

  • DashScope CosyVoice
  • 阿里云 DashScope
  • 宝塔面板
  • OpenCloudOS
  • RHEL 系统

解决方案

  • SSL_CERT_FILE 环境变量
  • REQUESTS_CA_BUNDLE 环境变量
  • certifi cacert.pem
  • Python 虚拟环境 SSL 配置
  • 宝塔 Python 项目 SSL 证书

问题现象

  • 本地正常服务器失败
  • WebSocket 握手超时
  • 宝塔部署 DashScope 语音合成失败
  • OpenCloudOS SSL 证书问题

如果您通过以上任何关键词搜索到本文,说明问题相似,请重点关注 "SSL_CERT_FILE" 和 "REQUESTS_CA_BUNDLE" 两个环境变量的配置。

标签: none

添加新评论