开发者网络指南:终端、Git、npm、Docker 与 API 调用怎么走机场
系统代理管不到终端、Docker 和大部分构建工具,这篇把每种工具各自的代理配置方式一次列全,可以直接复制使用。
先说清楚问题的根源:系统代理开关只对「愿意读取它」的程序有效,而开发者每天用的工具大多不读。 你在客户端里打开系统代理,浏览器立刻能上外网,但 git clone 依然超时、docker pull 依然卡住、pip install 依然报连接重置——因为它们遵循的是各自的环境变量和配置文件。
这篇把开发场景下需要配的每一处都列出来,命令可以直接复制。先给一个总原则:能开 TUN 就开 TUN,它在系统层接管流量,所有工具一次性覆盖;下面这些逐工具配置适用于不方便开 TUN 的场景(服务器、CI、容器内、需要精确控制某个工具时)。
为什么终端不走系统代理?
三种「代理生效方式」的作用范围完全不同,理解这张表能省掉大量无效排查。
| 方式 | 生效范围 | 需要权限 | 典型漏网之鱼 |
|---|---|---|---|
| 系统代理设置 | 主动读取该设置的应用 | 无 | 终端、Docker、Go、部分构建工具 |
| 环境变量 | 当前 shell 及其子进程 | 无 | 系统服务、守护进程、GUI 应用 |
| TUN / 虚拟网卡 | 整机所有 IP 流量 | 管理员 | 极少数直接操作网卡的程序 |
环境变量还有一个容易忽略的特性:它只对「设置之后启动的进程」生效。你在终端里 export 了变量,已经在后台跑着的服务不会感知到;反过来,在一个终端窗口设置的变量,另一个窗口也读不到。配完之后记得重开需要生效的进程。
终端环境变量怎么设?
先确认你的客户端本地监听端口。Clash 系客户端常见的是 HTTP 端口 7890、SOCKS5 端口 7891,也有合并成混合端口 7890 的。在客户端设置页能看到实际值,下面的示例统一用 7890。
临时生效(当前终端会话)
export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export all_proxy="socks5://127.0.0.1:7891"
export no_proxy="localhost,127.0.0.1,::1,192.168.0.0/16,10.0.0.0/8,*.internal.example.com"
# 部分工具只认大写形式,一起设更保险
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
export ALL_PROXY="$all_proxy"
export NO_PROXY="$no_proxy"
注意 https_proxy 的值写的是 http:// 而不是 https://——这里指的是「到代理服务器的连接用什么协议」,绝大多数本地客户端监听的是明文 HTTP,写成 https:// 会直接握手失败。这是最高频的配置错误。
验证是否生效:
curl -sS https://api.ipify.org # 应返回节点的出口 IP
curl -v https://example.com 2>&1 | head # 看是否经由代理建立连接
做成开关函数(推荐)
每次手打太麻烦,在 ~/.zshrc 或 ~/.bashrc 里加两个函数:
proxy_on() {
export http_proxy="http://127.0.0.1:7890"
export https_proxy="$http_proxy"
export all_proxy="socks5://127.0.0.1:7891"
export no_proxy="localhost,127.0.0.1,::1,192.168.0.0/16,10.0.0.0/8"
export HTTP_PROXY="$http_proxy" HTTPS_PROXY="$https_proxy" ALL_PROXY="$all_proxy" NO_PROXY="$no_proxy"
echo "proxy on -> $http_proxy"
}
proxy_off() {
unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY
echo "proxy off"
}
不建议无条件把 export 直接写进 shell 配置文件里。一旦客户端没启动,所有命令行工具都会去连一个不存在的端口,报错信息会非常具有误导性(通常是「连接被拒绝」,让人以为是网络问题)。
Windows 下的写法
PowerShell:
$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:NO_PROXY = "localhost,127.0.0.1,::1"
CMD:
set HTTP_PROXY=http://127.0.0.1:7890
set HTTPS_PROXY=http://127.0.0.1:7890
set NO_PROXY=localhost,127.0.0.1
WSL 里要注意:WSL2 有自己的虚拟网络,127.0.0.1 指向的是 WSL 自身而不是 Windows 宿主机。需要用宿主机在 WSL 网络中的地址,或者在客户端里开启「允许局域网连接」后指向宿主机 IP。
Git 怎么配代理?
Git 的代理配置独立于环境变量(虽然它也会读环境变量),而且 HTTPS 和 SSH 两种协议的配置方式完全不同。
HTTPS 方式
# 全局代理
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
# 查看当前设置
git config --global --get http.proxy
# 取消
git config --global --unset http.proxy
git config --global --unset https.proxy
更精细的做法是只给特定主机走代理,这样公司内网的 Git 服务器不受影响:
git config --global http.https://github.com/.proxy http://127.0.0.1:7890
这条配置的语法容易写错,注意 http. 之后是完整的 URL 前缀(含结尾斜杠),再接 .proxy。
SSH 方式
用 git@github.com: 形式的仓库地址时,上面的配置完全无效,因为走的是 SSH 协议。需要改 ~/.ssh/config:
Host github.com
HostName github.com
User git
# SOCKS5 方式(需要 nc 支持 -X)
ProxyCommand nc -X 5 -x 127.0.0.1:7891 %h %p
Host gitlab.com
HostName gitlab.com
User git
# 也可以用 corkscrew 走 HTTP 代理
ProxyCommand corkscrew 127.0.0.1 7890 %h %p
Linux 上如果 nc 不支持 -X,改用 ncat:
ProxyCommand ncat --proxy 127.0.0.1:7891 --proxy-type socks5 %h %p
Windows 的 OpenSSH 可以用内置的 connect 工具或直接用:
ProxyCommand connect -S 127.0.0.1:7891 %h %p
配完验证:
ssh -T git@github.com
如果 GitHub 只是慢而不是连不上,代理不一定是最优解,先看 GitHub 访问慢的排查里的其他手段。
包管理器怎么配?
每种语言的生态各配各的,下面按使用频率排列。
npm / yarn / pnpm
# npm
npm config set proxy http://127.0.0.1:7890
npm config set https-proxy http://127.0.0.1:7890
npm config get proxy
npm config delete proxy
npm config delete https-proxy
# yarn 1.x
yarn config set proxy http://127.0.0.1:7890
yarn config set https-proxy http://127.0.0.1:7890
# yarn 2+ / pnpm 主要读环境变量,设好 HTTP_PROXY/HTTPS_PROXY 即可
需要注意的是,npm 的部分子进程(比如安装时下载二进制的 node-gyp、electron、puppeteer)不走 npm 的代理配置,它们各有自己的环境变量。所以遇到「依赖装到一半卡在某个二进制下载」,光配 npm 代理没用,还要设好通用的 HTTP_PROXY/HTTPS_PROXY,或者直接开 TUN。
pip / Python
# 单次使用
pip install --proxy http://127.0.0.1:7890 requests
# 持久配置
pip config set global.proxy http://127.0.0.1:7890
pip config unset global.proxy
也可以写进配置文件(Linux/macOS 在 ~/.config/pip/pip.conf,Windows 在 %APPDATA%\pip\pip.ini):
[global]
proxy = http://127.0.0.1:7890
timeout = 60
requests、httpx 等库在运行时同样读 HTTP_PROXY/HTTPS_PROXY 环境变量,写脚本调用境外 API 时不需要额外改代码。
Go、Rust、Java
# Go:模块代理与直连例外
export GOPROXY=https://proxy.golang.org,direct
export GOPRIVATE=git.internal.example.com
# Go 的 http 客户端也读 HTTP_PROXY/HTTPS_PROXY
# Cargo:在 ~/.cargo/config.toml 中
# [http]
# proxy = "http://127.0.0.1:7890"
# Maven:在 ~/.m2/settings.xml 的 <proxies> 段落配置
# Gradle:在 gradle.properties 中设置 systemProp.http.proxyHost / proxyPort
Java 生态的一个特点是它不读环境变量,必须用 systemProp.* 或 JVM 参数 -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=7890。这一点经常被忽略,导致「所有工具都好了就 Gradle 不行」。
Docker 怎么配?
Docker 的代理要分三层配,很多人只配了其中一层,然后奇怪为什么还是不行。
第一层:daemon 拉取镜像的代理
docker pull 是由后台 daemon 发起的,和你终端里的环境变量无关。Linux 下用 systemd drop-in:
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf >/dev/null <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,.internal.example.com"
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
systemctl show --property=Environment docker # 验证
Docker Desktop(macOS / Windows)在图形界面的 Settings → Resources → Proxies 里设置即可,不用改文件。
第二层:构建时(build)的代理
构建过程中容器内执行的 apt-get、npm install 需要单独传入:
docker build \
--build-arg HTTP_PROXY=http://host.docker.internal:7890 \
--build-arg HTTPS_PROXY=http://host.docker.internal:7890 \
--build-arg NO_PROXY=localhost,127.0.0.1 \
-t myapp .
不要把代理地址硬编码进 Dockerfile 的 ENV,否则镜像被别人拉去用时会试图连一个不存在的代理。用 ARG 传入,只在构建期生效。
第三层:运行时容器内的代理
docker run --rm \
--add-host=host.docker.internal:host-gateway \
-e HTTP_PROXY=http://host.docker.internal:7890 \
-e HTTPS_PROXY=http://host.docker.internal:7890 \
-e NO_PROXY=localhost,127.0.0.1 \
alpine sh -c "apk add --no-cache curl && curl -sS https://api.ipify.org"
或者写进 ~/.docker/config.json,让所有容器默认带上:
{
"proxies": {
"default": {
"httpProxy": "http://host.docker.internal:7890",
"httpsProxy": "http://host.docker.internal:7890",
"noProxy": "localhost,127.0.0.1"
}
}
}
http://127.0.0.1:7890 必定失败。Linux 下需要显式加 --add-host=host.docker.internal:host-gateway,或者直接用宿主机在 docker0 网桥上的地址。同时客户端要开启「允许局域网连接」,否则它只监听回环地址,容器根本连不上。docker compose 里同样用 environment 段传入,并在 extra_hosts 中加上 host-gateway 映射。
API 调用要注意什么?
调用境外 API(尤其是 AI 服务的 API)时,配置正确只是及格线,还有三件事决定成败。
第一,出口 IP 必须固定。 客户端如果用「自动选择延迟最低」或负载均衡,每次请求的出口可能不同,服务端会判定为异常访问。正确做法是给 API 域名写一条独立规则,指向固定节点:
# Clash 规则示例,放在所有规则集之前
DOMAIN-SUFFIX,api.openai.com,美国原生-固定
DOMAIN-SUFFIX,api.anthropic.com,美国原生-固定
规则的完整写法和优先级规则见自定义分流规则,策略组的分层设计见进阶指南。
第二,超时要放宽。 AI API 的流式响应可能持续几十秒,默认的 HTTP 客户端超时(常见 30 秒)会在中途断开。SDK 里显式设置一个更长的读超时,同时确认代理链路上没有更短的空闲超时。
第三,重试策略要区分错误类型。 网络层面的连接重置可以重试,服务端返回的限流应该按退避策略等待,而认证失败重试没有任何意义还会加速触发风控。
编辑器内的 AI 助手(Copilot、Cursor 等)是同一类问题,但它们有自己的代理设置项和证书要求,单独整理在 Cursor 与 Copilot 网络配置里。
远程服务器和 CI 环境怎么处理?
本地开机器可以开 TUN,但服务器和流水线环境没有这个选项,配置思路也不一样。
远程开发服务器(你 SSH 上去写代码的那台)有两种做法。一是在服务器本地跑一份代理客户端,用同一条订阅,然后按前面的方式设环境变量;二是不在服务器上装代理,而是通过本地机器反向转发一个端口过去:
# 把本地的 7890 端口映射到远程机器的 7890
ssh -R 7890:127.0.0.1:7890 user@remote-host
# 登录后在远程机器上:
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
第二种方式的好处是订阅凭证不落在服务器上,断开 SSH 后代理也自动失效,适合临时拉一次依赖的场景。注意远程的 sshd 若限制了端口转发,这条命令会静默失败,先确认配置允许。
CI 与构建环境里通常不该用个人机场。原因有三个:订阅凭证会以密文形式存进 CI 的变量里,权限管理比本地宽松得多;构建机的出口 IP 会被大量并发请求占用,容易触发上游限流;机场一旦故障,整条流水线跟着挂。更合理的做法是给 CI 配置镜像源或企业级的出站代理,把个人机场留给本地开发。
容器化的开发环境(Dev Container、远程容器)要注意代理地址会随环境变化:本地跑的容器指向宿主机网关,远程跑的容器指向的是远端宿主机而不是你的笔记本。把代理地址写成可配置的环境变量而不是硬编码,换环境时只改一处。
常见坑与排查顺序
按遇到的频率排序,附最快的验证方式。
| 症状 | 最可能的原因 | 验证 |
|---|---|---|
| 终端全部工具连不上,浏览器正常 | 环境变量没设或端口写错 | echo $http_proxy、curl -sS https://api.ipify.org |
| 设了变量仍不生效 | 变量在设置前启动的进程里不生效 | 重开终端或重启服务 |
https_proxy 报 TLS 错误 | 值写成了 https:// | 改回 http:// |
| 只有 Gradle/Maven 不行 | Java 不读环境变量 | 加 -Dhttp.proxyHost 参数 |
| 容器内连不上代理 | 用了 127.0.0.1 或客户端未允许局域网 | 容器内 curl 宿主机地址 |
docker pull 不走代理 | 只配了终端没配 daemon | systemctl show --property=Environment docker |
| 内网服务也走了代理 | 没配 no_proxy | 检查 echo $no_proxy |
| 自签名证书错误 | 客户端开了 TLS 解密,或企业根证书未信任 | 关闭客户端解密功能 |
| SSH 走代理失败 | nc 不支持 -X | 换 ncat 或 corkscrew |
| 大文件 push 中途失败 | 节点连接存活时间短 | 换专线节点,git config --global http.postBuffer 524288000 |
git config http.sslVerify false、npm config set strict-ssl false、pip --trusted-host)能让命令跑通,但会让所有依赖下载失去完整性保证。它只适合一次性的临时排查,用完立刻改回来,绝不要写进团队的配置模板。开发场景对机场本身的要求
最后回到选机场这件事。开发用途和看视频的需求不同,优先级依次是:
- 连接存活时间。
git push一个大仓库、上传构建产物、跑长时间的 API 请求,中途断连比慢十倍更致命。选之前一定要测长连接,测法见稳定机场的判断方法。 - 延迟抖动小。SSH 和交互式终端对抖动极其敏感,专线在这一点上优势明显。
- 出口 IP 稳定且干净。调 API 需要固定 IP,原生 IP 触发风控的概率明显更低。
- 同时提供 HTTP 和 SOCKS5 端口。有些工具只支持其中一种。
- 支持精细分流。内网、镜像源、公司服务必须能直连。
带宽反而排在最后——拉代码和调 API 消耗的带宽很小,你需要的是稳定的下限,不是漂亮的峰值。按这个优先级去看机场推荐里的专线档位,通常比在性价比档里反复折腾更省时间。