
同一个 API,为什么系统 curl 失败而 Homebrew curl 成功?
本文针对在国内云服务器(阿里云、腾讯云等)上部署 Web 服务时遇到的 HTTPS 连接问题,探寻 “同一个 API,为什么系统 curl 失败而 Homebrew curl 成功?”。
适用场景:本文针对在国内云服务器(阿里云、腾讯云等)上部署 Web 服务时遇到的 HTTPS 连接问题。如果你的服务部署在海外服务器,不会遇到本文描述的问题。
问题现象
在阿里云服务器上部署了一个 API 服务,使用 Caddy 作为反向代理,绑定域名 api.example.com。服务在本地测试一切正常,但从外部访问时出现诡异现象:
同样是 curl 命令,为什么有的成功有的失败?这个问题困扰了我好几个小时。
同样是 curl 命令,为什么有的成功有的失败?这个问题困扰了我好几个小时。
排查过程
第一阶段:怀疑代理问题
最初注意到失败的请求解析到了 198.18.x.x(代理软件的虚拟 IP 段),而成功的请求也解析到类似地址。查看 Clash 连接日志后发现:
两个请求的代理配置完全一致,都是直连到同一个 IP,排除代理路由问题。
第二阶段:怀疑 TLS 指纹
既然代理配置相同,区别只能在 curl 本身。对比两个版本:
- 系统 curl:使用 LibreSSL / Secure Transport
- Homebrew curl:使用 OpenSSL + Apple SecTrust
难道是阿里云对某些 TLS Client Hello 特征进行过滤?这个方向看似合理,但缺乏直接证据。
第三阶段:检查服务端配置
登录阿里云服务器,逐一排查:
服务端配置没有问题,Caddy 和后端服务都运行正常。
第四阶段:tcpdump 抓包(关键突破)
在 Caddy 服务器上抓包,同时从海外服务器发起请求:
抓包结果揭示了关键信息:
关键发现:RST 包在 ACK 之后仅 4 微秒就到达了。从海外服务器到国内的网络延迟至少几十毫秒,4 微秒内返回 RST 是不可能的——这说明 RST 是阿里云边缘设备发出的,而非真正的服务器。
第五阶段:HTTP 测试(真相大白)
既然 HTTPS 在 TLS 层被拦截,那用 HTTP 绕过 TLS 试试:
返回结果:
真相大白:返回了 ICP 备案拦截页面。问题根本不是 TLS 指纹,而是域名没有完成 ICP 备案。
根因分析
阿里云的 ICP 备案检测机制
阿里云对托管在国内服务器上的网站强制要求 ICP 备案。其边缘安全设施会在流量到达服务器前进行检测:
拦截策略的差异
为什么不同来源表现不同?
阿里云对海外 IP 访问未备案域名的检测最为严格,几乎 100% 拦截。对国内 IP 的检测相对宽松,但某些 TLS 指纹仍可能触发拦截。
回到最初的问题:为什么两个 curl 表现不同?
通过 Clash 日志确认,两个 curl 的代理配置完全一致——都是 DIRECT 直连,都连接到同一个服务器 IP。那为什么一个成功一个失败?
答案在于 TLS 实现的差异:
不同的 TLS 库在发送 Client Hello 时,会有不同的:
- Cipher Suites 顺序
- TLS 扩展列表
- 支持的椭圆曲线
阿里云的边缘检测设备会分析这些特征。对于未备案域名,某些 TLS 指纹(特别是看起来像"脚本/爬虫"的特征)更容易触发拦截,而看起来像"正常浏览器"的指纹则可能被放行。
这也解释了为什么问题表现得如此诡异——同一台电脑、同一个网络、同一个目标,仅仅因为 curl 版本不同就产生了截然不同的结果。本质上,这是 ICP 备案检测 + TLS 指纹识别共同作用的结果。
解决方案
将域名换成已完成 ICP 备案的域名,重新配置 Caddy 后,所有 curl 版本都能正常访问:
经验总结
1. 国内服务器部署的铁律
在国内服务器上提供 Web 服务,域名必须完成 ICP 备案。 这不是建议,是强制要求。
2. ICP 拦截问题的排查方法
3. 部署位置选择原则
个人使用情况总结如上,不一定适合所有。
4. 避免踩坑的建议
- 域名规划:提前准备已备案域名用于国内服务
- DNS 选择:国内服务使用国内 DNS 服务商(阿里云解析等)
- 测试覆盖:上线前从不同网络环境(国内/海外、不同运营商)测试访问
写在最后
这次排查走了不少弯路,从代理配置到 TLS 指纹,最后才发现是 ICP 备案这个"基础设施级"的问题。
回过头看,HTTP 测试是最简单直接的排查方法——绕过 TLS 直接暴露真正的拦截原因。而 tcpdump 抓包则提供了底层视角,4 微秒返回 RST 这个细节直接指向了"边缘设备拦截"的结论。
技术问题的排查就像侦探破案,证据链完整了,真相自然浮出水面。



