公司内网连不上 AI 编程工具:代理、证书链、DNS 三段排查法
数据截至 2026-07,各产品的额度与报错口径以官方最新说明为准。
在公司内网连不上 AI 编程工具,第一反应往往是”这工具在国内用不了”,而真正的卡点常常在本机到出口这段路上:代理没被进程读到、企业中间设备重签的证书链没进信任库、或者域名在内部 DNS 那里被解析成了别的东西。 这三段的报错长得像,处置动作完全不同,凭感觉换工具、重装、改镜像源,多半只是把时间花掉。
本篇只管网络层。站内的 Claude Code 安装报错排查 和 Codex 安装失败排查 处理的是”包装不上”——运行时版本、安装方式、目录权限那一类;本篇假设你已经装好了,命令能启动,问题是请求出不去。两边配合看:先确认二进制是好的,再来查这条路。
一、先把”连不上”拆成三段
一次 HTTPS 请求从本机出去要过三道:名字解析(域名变成地址,或交给代理去解析)、连接建立(TCP 到目标或到代理端口)、TLS 握手(校验对方证书链)。三道过完才有 HTTP 状态码。所以只要看到了状态码——401、403、429、500 都算——网络这条路已经通了,剩下的是凭据和服务端的事。
定位靠一条命令就够,关键是会读输出的分段:
curl -v https://example.com/ -o /dev/null
从上往下看这几行:解析出的地址、Connected to 后面接的是目标还是代理端口、有没有 CONNECT 隧道行、TLS 握手成功还是报证书错、最后有没有状态行。断在哪一行就落在哪一段。这个读法对 git、包管理器、AI 编程工具通用,它们底层跑的是同一套网络栈。
先对判别表,再翻对应小节。
| 现象 | 大概率成因 | 怎么验证 | 处置动作 |
|---|---|---|---|
| 立刻失败,连接被拒(ECONNREFUSED) | 代理地址或端口写错,或代理服务没在监听 | curl -v 看连的是哪个端口;用 nc -vz <代理主机> <端口> 单独探 | 校正代理地址端口,确认代理在你所在网段可达 |
| 卡很久后超时(ETIMEDOUT) | 出网被防火墙丢包,或进程根本没走代理、直连出去了 | 带变量和不带变量各跑一次 curl -v,看有没有 CONNECT 行 | 补齐代理变量并确认目标进程读到了它 |
| 报证书链校验失败(自签根证书不被信任) | 中间设备做 TLS 解密并用企业 CA 重签,该根证书不在校验用的信任库里 | openssl s_client 看证书的颁发者是不是公司内部 CA | 把企业根证书装进系统信任库,再逐个运行时指过去 |
| 代理返回 407 | 代理要求认证,凭据没带上 | 用带凭据的 curl 请求同一个 URL 对照 | 按公司规定的方式配代理认证,别把明文口令散在 shell 配置里 |
| 域名解析不到,或解析到一个内网地址 | 内部 DNS 没有该记录,或被解析到拦截页 | getent hosts <域名>、dig +short <域名> 对照 | 让解析交给代理远端做,或走流程让网络组补记录 |
| 首次能通,之后偶发连接被重置(ECONNRESET) | 长连接被中间设备按会话超时掐断 | 观察是否只在流式响应或长耗时请求上出现 | 缩短单次请求、改用非流式输出,被重置后做有限次重试;会话超时策略要找网络组 |
| 已经拿到 401/403/429 等状态码 | 网络已通,问题在凭据、配额或网关策略 | 看响应体是网关拦截页还是服务端返回的结构化错误 | 切轨到服务端排查,不再动网络配置 |
最后一行是最容易被浪费时间的一格。拿到状态码就该换方向,走 OpenAI API 报错排查 或 Claude API 报错排查 那条线,而不是继续调代理。
二、代理这一段:为什么”配了却没生效”
企业网里出网基本都要过代理。约定俗成的四个环境变量是 http_proxy、https_proxy、all_proxy、no_proxy,各家运行时还会各读一份大写形式。先看事实:
env | grep -i proxy
配了没生效,常见是下面这几种情形,每一种的判别方式都不同。
一是作用域不对。终端里 export 只影响当前 shell 和它之后拉起的子进程;图形界面启动的编辑器、桌面客户端、后台守护进程,环境来自登录会话或服务单元,不读你后开的那个终端。判别方法:从这个终端把工具启动一次,通了就是作用域问题,该写进登录级配置并重新登录,或写进对应的服务环境文件。
二是协议前缀写错。https_proxy 指的是”访问 https 目标时用哪个代理”,不是”用 https 连代理”。企业代理绝大多数是 HTTP CONNECT 隧道,值应该是 http://主机:端口;写成 https:// 会在连代理这一跳先做一次 TLS,通常直接失败。
三是 no_proxy 的匹配规则各实现不一致:有的做后缀匹配,有的要带前导点,有的不认 CIDR,有的忽略端口。一次写一长串以为万无一失,实际内网地址照样被送去代理。稳妥做法是只写最保守的域名后缀形式,写一条验证一条。
四是有些客户端不读环境变量,只认自己的配置,git 是典型:
git config --global http.proxy http://proxy.example.internal:8080
git config --global --get http.proxy
包管理器、容器守护进程也各有一套,“系统层配好了”不等于”这个工具配好了”。
五是子进程链断了。AI 编程工具常会拉起额外进程去跑工具调用或本地服务,主进程能出网不代表这些子进程继承到了变量,症状是”主对话正常,某个能力一调就超时”,思路见 Claude Code MCP 报错处理。
需要认证的代理,用户名口令属于公司凭据,别塞进环境变量再提交到仓库,也别写进项目脚本,原则和 API 密钥一样,参考 API 密钥安全管理。
三、证书这一段:装到哪个信任库才算数
TCP 已经连上、握手却报证书链校验失败(提示大意是拿不到签发者,或链上出现自签证书),机制基本是确定的:出口有设备做 TLS 解密再重签,客户端看到的颁发者是公司内部 CA;这个 CA 的根证书不在”当次校验实际使用的那个信任库”里,校验就过不去。
先取证,看清对方是谁:
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -E "^(subject|issuer)"
颁发者出现公司名字,就是重签,方向确定。
接下来是最容易返工的一点:系统信任库不等于运行时信任库。Node 自带一份根证书列表,Python 的 requests 默认用 certifi 打包的那份,Java 有自己的 keystore,git 则取决于编译时链的是哪个 TLS 后端。只把证书装进操作系统,Node 和 Python 照样报错。
顺序上先装系统,再逐个运行时补。系统层(Debian 系与 RHEL 系路径不同,装完都要跑一次刷新命令):
# Debian/Ubuntu
sudo cp corp-root-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# RHEL/CentOS
sudo cp corp-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract
运行时层用各自的入口,指向一个包含企业根证书的 PEM 文件:
export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/corp-root-ca.pem
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/corp-bundle.pem
export SSL_CERT_FILE=/etc/ssl/certs/corp-bundle.pem
git config --global http.sslCAInfo /etc/ssl/certs/corp-bundle.pem
想知道 Python 当前实际在用哪份,直接问它:
python -c "import certifi; print(certifi.where())"
追加根证书到 bundle 时,先确认原文件末尾有换行。少一个换行会让两个 PEM 块粘成一行导致整个文件解析失败,表现是”装了证书反而更多域名报错”。追加完用 openssl x509 -in <文件> -noout -subject 解析一遍确认。
关闭证书校验只能当一次性判定信号——关掉就通,说明问题确实在证书段——但不该留下来。一旦落进项目配置、镜像或流水线,等于对所有 HTTPS 目标放弃校验,风险对整台机器生效,接手的人还看不出来。真要用,只在当前那条命令的环境里出现,验证完立刻撤掉。
四、DNS 这一段:解析在哪一端做
DNS 问题分两类:解析不到,和解析到了不该去的地址。后者更阴,请求会走完,只是走到了拦截页或某个内网服务,报错看起来像证书错或 404。
getent hosts example.com
dig +short example.com
两条命令的适用面不一样,别在报”命令不存在”的时候误判成解析失败:getent 来自 glibc,只在 Linux 上有;macOS 查系统解析用 dscacheutil -q host -a name example.com,Windows 上用 nslookup example.com。dig 属于 DNS 工具包(Debian 系在 dnsutils、RHEL 系在 bind-utils),精简镜像里经常没装,容器内排查先确认它在不在。两者的区别也值得记一下:getent 走的是系统解析器配置(会命中 hosts 文件、NSS 里的其他数据源),dig 直接向 DNS 服务器发查询、默认不看 hosts 文件。两条结果不一致,往往就是有人在 hosts 文件里留了一行手写记录。
代理场景下有个关键区分:解析在本地做还是远端做。走 HTTP CONNECT 隧道时域名交给代理去解析,本机 dig 查不到也可能一切正常;SOCKS 代理则要看具体用法,解析在客户端还是代理端是两种行为,会直接造成”浏览器能开、命令行不行”这类分裂现象。所以在代理环境里,本机解析失败不能单独作为结论,要和 curl -v 的连接行对照。
想验证”是不是解析走偏了”,可以绕开解析直接指地址试:
curl -v --resolve example.com:443:203.0.113.10 https://example.com/
指定地址后通了,成因就落在解析和分流上,不在代理或证书。分流配置(PAC、DNS 视图)会让同一台机器在不同网段表现不同——换个会议室或连上 VPN 后行为变化,通常就是这个。这种别自己硬调,把域名、解析结果、所在网络和时间记下来提给网络组,对方能直接查到命中了哪条策略。
还有一类必须说清:部分海外 AI 工具与模型服务,官方明确对中国大陆地区有区域限制、不支持直连。这种情况网络层无论怎么配都不会通,改代理改证书都是白做。市面上存在第三方中转服务,本篇不做推荐、不评价其稳定性与合规性,账号与付费上的现实约束可以看 海外 AI 工具充值。判断依据是:先确认目标服务在你所在地区是否受支持,再决定要不要继续排查。
五、什么情况下别再折腾
网络排查真正的成本不是难,是没有止损意识:改一处试一次,一下午过去,机器上多了十几处说不清来历的配置。给自己划几条线。
出现下面任一情况,停手,问题不在你的机器上:
- 代理端口本身连不上(探端口就失败)。这是网络可达性或权限问题,继续改环境变量不会有任何变化。
- 临时关闭证书校验后依然不通。说明卡点不在证书段,你正在错误的方向上加深。
- 同网段另一台干净机器或干净容器表现一样。样本从 1 变成 2,结论就从”我的机器坏了”变成”这条路没开”,该走网络组的流程。
- 目标服务在你所在地区不受官方支持。这是策略层,不是配置层。
- 拿不到公司根证书的正式来源。不要从聊天记录、网盘里捡一个来历不明的 PEM 装进系统信任库,那比连不上危险得多。
回滚点要在动手之前准备好:开一个临时文件,记下环境变量写进了哪个文件、git config 改了哪几个键、往信任库放了哪个文件、给哪个运行时设了变量。原则是尽量只改用户级配置,装根证书是唯一必须动系统级的地方。排查失败就照单子倒着撤,让机器回到干净状态再来,而不是在半成品配置上继续叠。
换条路的判断依据:团队里已经有人在同样的网络里跑通了,就照抄对方的改动清单,别自己重新推一遍;如果全组都要过这道坎,让运维把代理和证书下发做成统一配置,由一处维护——每个人各配一遍,就是每个人各留一套没人清理的历史包袱。
六、避坑清单
终端里配好了,编辑器里还是不通。 会踩是因为直觉认为环境变量是全局的,实际图形进程的环境来自登录会话。避法:验证时统一从终端启动被测进程,确认结论后再写进登录级配置并重新登录。
https_proxy 的值写成了 https://。 会踩是因为”访问 https 就该用 https 连代理”这个错觉。避法:记住这个变量描述的是目标协议不是代理协议,企业 CONNECT 代理一律写 http://。
no_proxy 写了却没排除掉。 会踩是因为各实现对通配符、端口、网段的支持不一致,一次写一长串就没法定位哪条失效。避法:一次只加一条最保守的域名后缀,加完立刻用一次请求验证。
只装了系统信任库就以为完事。 会踩是因为不知道运行时自带根证书列表。避法:装完系统层,Node、Python、git 各自用一条最小请求单独验证一次,全绿才算完。
追加证书后更多域名报错了。 会踩是因为拼接 PEM 时缺了换行,整个 bundle 解析失败。避法:追加前确认末尾有换行,追加后用 openssl 把文件解析一遍。
关闭校验的开关留在了配置里。 会踩是因为排查时图快,随手写进了项目配置或镜像构建。避法:这类开关只允许出现在单条命令的环境里,排查结束在仓库里搜一遍关键字确认没落盘。
把根证书或代理凭据提交进了仓库。 会踩是因为想让同事一键复现,顺手一起提交了。避法:证书走内部配置管理或文档下发,凭据用系统凭据存储,仓库里只留占位和说明。
只在自己机器上反复试。 会踩是因为手边只有一台机器,样本量 1 无法区分个体问题和策略问题。避法:尽早在干净容器或同事机器上复现一次,这一步往往比多改五处配置更省时间。
把 429、401 也当网络问题查。 会踩是因为报错都表现为”用不了”。避法:拿到 HTTP 状态码就换轨——网络已经通了,剩下的是配额、凭据或网关策略。
收束
这三段的顺序不是随便排的:代理决定请求走哪条路,证书决定这条路上的握手能不能过,DNS 决定终点是不是你要的那个。按顺序查,每一步都有独立的验证命令,不会出现”改了三处不知道哪处起了作用”。下次卡住照这份清单走一遍:
curl -v跑一次,确认断在解析、连接、握手还是状态码,先把段定下来。env | grep -i proxy看变量,并从终端直接启动被测进程,确认它真读到了。- 用
openssl s_client看证书颁发者,判断是不是企业 CA 重签。 - 系统信任库和各运行时信任库分别验证一次,不要只做一半。
getent hosts与dig对照,代理环境下再用--resolve定向验证一次。- 拿到任何 HTTP 状态码就停止排查网络,切到服务端方向。
- 结束前对照改动清单,把临时开关和临时配置全部撤掉。