Linux curl 报错 35 怎么办?TLS 握手失败、SNI 与代理配置排查
本内容发表于:2026-09-10 11:40:53
浏览量
1051

TLS 握手连接点排查示意图

Linux 服务器调用 HTTPS 接口时出现 curl: (35),只凭这一行无法判断是证书、协议还是网络设备出了问题。curl 将错误 35 定义为 SSL/TLS 握手阶段发生异常;具体原因需要结合后面的错误文本、实际连接地址和 TLS 后端判断。[1]

本文围绕一次 HTTPS 请求展开排查:记录失败现场,确认域名与连接 IP,再对比 TLS 版本和代理路径,最后检查服务端日志。下面是诊断示例,未在你的生产环境执行,也不代表 CloudFlew 当前服务存在故障。

适用范围:Linux 上的 curl 与 OpenSSL 命令行。示例中的 example.com 和 203.0.113.10 是占位值,执行前替换为你有权测试的域名与 IP。只访问无副作用的测试路径,不携带生产 Cookie、令牌或业务数据;命令选项以本机版本帮助为准。

一、先区分错误 35、错误 60 和 HTTP 状态码

错误 35 表示握手过程失败,可能涉及协议协商、证书相关配置或连接被中断。错误 60 通常指向对端证书校验失败,例如信任链或主机名校验没有通过。两者不能混用同一套修复结论。[1]

HTTP 403、502 等状态码属于 HTTP 层。如果 curl 已经收到了 CDN 返回的 HTTP 响应,至少说明客户端到这个响应节点的 TLS 会话已建立;后续仍可能是 CDN 到源站的连接失败。排查时要写清楚“哪一段连接”出错,避免把源站问题当成客户端握手问题。

二、记录失败现场,不要一上来加 -k

curl -V
openssl version
curl -v --connect-timeout 10 --max-time 20 \
  --output /dev/null https://example.com/

curl -V 用于确认 curl 版本、TLS 库和编译能力。系统里的 openssl 命令不一定与 curl 使用相同的库或证书存储,因此两个工具表现不同并不矛盾。[2]

查看详细输出时,记录实际连接的 IP、是否使用代理、连接是否已经建立,以及 SSL_connect 后面的错误文字。连接超时、被重置、protocol version 和 certificate verify failed 是不同线索。单独看到 SSL_ERROR_SYSCALL,仍不足以锁定根因。

-v 输出可能包含请求头、认证信息或内部地址。对外分享前应脱敏,不要把带令牌的完整日志放进工单或公开文章。示例设置了连接和总耗时上限,避免一次诊断请求长时间占用终端。[2]

不建议把 -k 或 --insecure 写成修复步骤。它跳过证书验证,会降低连接安全性,而且无法解决大多数协议不兼容或连接中断。若出现错误 60,应修复证书链、域名匹配、系统时间或受信任 CA 配置,而不是永久关闭验证。[1][2]

三、测试指定 IP 时保留域名与 SNI

排查多节点服务时,直接请求 https://IP/ 再添加 Host 请求头,不能完整模拟正常域名访问。TLS 握手发生在 HTTP 请求发送前,Host 请求头不能代替握手中的 SNI。证书名称校验也取决于 URL 中的主机名。

curl -v --connect-timeout 10 --max-time 20 \
  --resolve example.com:443:203.0.113.10 \
  --output /dev/null https://example.com/

--resolve 为本次命令提供指定的主机名、端口与 IP 映射。URL 仍使用域名,适合在保持域名身份的前提下比较你有权测试的节点。[2]

该对照应在确认直连、未经过显式代理的环境进行;经过代理时,连接目标可能由代理决定,不能仅凭 --resolve 就认定命中了指定源站。也不要为了测试绕过组织规定的出口限制。

如果一个 IP 正常、另一个 IP 失败,优先对比对应节点的证书部署、监听配置、TLS 策略和网络路径。这是缩小范围的证据,不能仅凭一次结果宣布 DNS 或 CDN 有故障。直连源站还必须得到允许;某些源站只接受 CDN 回源流量,拒绝直连属于预期行为。

四、用 OpenSSL 观察握手与证书

timeout 20s openssl s_client \
  -connect 203.0.113.10:443 \
  -servername example.com \
  -verify_hostname example.com \
  -verify_return_error -showcerts </dev/null

这里用 -servername 显式发送域名 SNI,用 -verify_hostname 检查证书主机名,并通过 -verify_return_error 让证书校验失败时终止。没有后一项时,s_client 作为诊断工具可能在显示校验错误后继续连接。[3]

-showcerts 展示服务端实际发来的证书列表,不等于已经验证通过的完整证书链。请同时看校验结果、协商协议和服务端告警。私有 CA 环境要使用管理员提供的可信 CA 文件,不能从报错页面随意下载证书并加入信任。[3]

示例里的 timeout 来自常见 Linux 工具集,用于限制诊断时长。若本机没有该命令,可在受控终端中执行 openssl s_client,并在检查后主动结束。OpenSSL 与 curl 的 TLS 后端、CA 路径和代理配置可能不同,比较结果时要把这些差异一起记录。

五、对比 TLS 1.2 与 TLS 1.3

curl -v --tlsv1.2 --tls-max 1.2 \
  --connect-timeout 10 --max-time 20 \
  --output /dev/null https://example.com/

curl -v --tlsv1.3 --tls-max 1.3 \
  --connect-timeout 10 --max-time 20 \
  --output /dev/null https://example.com/

--tlsv1.2 的意思是最低使用 TLS 1.2,不是只使用 TLS 1.2;需要配合 --tls-max 1.2 才能把测试范围限定在这个版本。TLS 1.3 测试则要求本机 curl 的 TLS 后端支持该版本。[2]

如果 TLS 1.2 成功、TLS 1.3 失败,下一步检查客户端能力、服务端策略以及路径上的代理或安全设备。测试时尽量保持节点和网络路径一致;否则版本差异可能与节点差异混在一起。不要据此全站关闭 TLS 1.3,也不要直接放开旧协议或低安全级别密码套件。

六、检查 HTTPS_PROXY 与代理协议是否写对

浏览器能打开、服务器 curl 失败时,两个客户端可能使用了不同代理、TLS 库或信任库。curl 可以读取 HTTPS_PROXY、ALL_PROXY、NO_PROXY 等环境变量;此外,默认配置文件也可能影响行为。只在本地检查配置,不要直接输出含用户名和密码的完整代理地址。[2]

HTTPS_PROXY 变量名表示它用于访问 HTTPS 目标,变量值中的 http:// 或 https:// 则描述客户端如何连接代理。普通 HTTP CONNECT 代理可以服务 HTTPS 目标;把一个只接受明文 HTTP 的代理端口误写为 https://,可能引发 wrong version number 等错误。仍需结合详细输出确认,不能把所有同名错误都归于代理。

仅在组织允许直连的环境,可以进行下面这个单次对照:

curl -q --noproxy '*' -v \
  --connect-timeout 10 --max-time 20 \
  --output /dev/null https://example.com/

-q 放在第一个参数位置,用于不加载默认 curl 配置文件;--noproxy 的星号让这次请求不使用 curl 配置的显式代理。它不会绕过透明代理、防火墙或出口网关,也不会修改系统代理设置。若公司要求统一代理,跳过此测试,由网络管理员核查代理日志。[2]

七、把客户端时间点与服务端日志对应起来

如果域名、节点和代理路径已经明确,但握手仍失败,收集同一时间段的 TLS 终止节点日志。该节点可能是 CDN、负载均衡器或反向代理,而不是应用服务器。记录测试时间及其时区、目标 IP、域名、协议版本和脱敏错误行。

重点查找协议版本限制、密码套件不匹配、要求客户端证书、虚拟主机未匹配和连接重置等线索。要求双向 TLS 的接口需要有效的客户端证书和私钥,应按服务方要求配置;私钥不能上传到公共诊断网站。

没有服务端日志时,可把脱敏证据交给服务提供方。不建议为了验证猜测直接修改内核参数、关闭 WAF 或重启整台服务器,这些动作既可能影响业务,也容易清掉现场。

八、修复后如何确认问题结束

修复证书、代理地址或服务端策略后,用原来的业务访问方式重测,而不只复用临时诊断参数。恢复正常域名解析,保持证书验证开启,再检查原先失败的路径是否得到预期 HTTP 响应;需要认证的接口返回 401,不等于 TLS 仍然失败。

在原来失败的客户端环境做少量重复验证,并查看对应服务端日志。若调整了生产配置,先备份原值,通过变更流程小范围验证;出现异常时恢复原配置。本文的 curl 选项只影响当前命令,移除即可恢复常规测试方式,不涉及持久化内核改动。

常见问题

curl 报错 35,一定是证书过期吗?

不是。35 是握手失败的错误类别,证书校验失败通常对应 60。应以详细错误文本和校验结果判断,不能只看错误编号就更换证书。[1]

能 ping 通,为什么 HTTPS 仍然失败?

ping 成功不证明 TCP 443 端口可达,也不证明 TLS 协商能完成。需要在实际 HTTPS 路径上测试,并区分连接建立前的失败与握手阶段的失败。

加 -k 后成功,可以一直这样用吗?

不建议。跳过校验可能让客户端接受伪造证书,无法作为生产修复方案。应定位并修复信任链、主机名或 CA 配置问题。[2]

结语

处理 curl 错误 35 时,一份有效记录应包含目标域名、实际 IP、curl 与 TLS 库版本、代理路径和完整的脱敏错误行。把这些信息放在一起,再逐项对比节点与协议,就能减少盲目改证书、降级 TLS 和重启服务的尝试。

参考资料

1. curl 官方:libcurl 错误代码

2. curl 官方:命令行参数、代理与证书验证

3. OpenSSL 官方:openssl s_client

资料核对日期:2026年9月10日。示例参数和行为以实际安装版本及其对应官方文档为准。