新手与进阶指南 进阶 高级

开发者网络指南:终端、Git、npm、Docker 与 API 调用怎么走机场

系统代理管不到终端、Docker 和大部分构建工具,这篇把每种工具各自的代理配置方式一次列全,可以直接复制使用。

发布: 更新: 审阅: 约 9 分钟阅读

先说清楚问题的根源:系统代理开关只对「愿意读取它」的程序有效,而开发者每天用的工具大多不读。 你在客户端里打开系统代理,浏览器立刻能上外网,但 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"
    }
  }
}
最高频的错误容器里的 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 不走代理只配了终端没配 daemonsystemctl 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)能让命令跑通,但会让所有依赖下载失去完整性保证。它只适合一次性的临时排查,用完立刻改回来,绝不要写进团队的配置模板。

开发场景对机场本身的要求

最后回到选机场这件事。开发用途和看视频的需求不同,优先级依次是:

  1. 连接存活时间。git push 一个大仓库、上传构建产物、跑长时间的 API 请求,中途断连比慢十倍更致命。选之前一定要测长连接,测法见稳定机场的判断方法。
  2. 延迟抖动小。SSH 和交互式终端对抖动极其敏感,专线在这一点上优势明显。
  3. 出口 IP 稳定且干净。调 API 需要固定 IP,原生 IP 触发风控的概率明显更低。
  4. 同时提供 HTTP 和 SOCKS5 端口。有些工具只支持其中一种。
  5. 支持精细分流。内网、镜像源、公司服务必须能直连。

带宽反而排在最后——拉代码和调 API 消耗的带宽很小,你需要的是稳定的下限,不是漂亮的峰值。按这个优先级去看机场推荐里的专线档位,通常比在性价比档里反复折腾更省时间。

常见问题

为什么开了系统代理,终端里还是连不上?
系统代理是一项配置声明,只有主动读取它的程序才会遵守。浏览器和多数 GUI 应用会读,而 curl、git、npm、go、docker 这类命令行工具遵循的是环境变量或各自的配置文件,两者互不相干。解决办法有两个:给终端设置代理环境变量,或者在客户端开启 TUN 模式接管整机流量,后者对所有工具一次性生效。
all_proxy、http_proxy、https_proxy 有什么区别?
http_proxy 用于 HTTP 请求,https_proxy 用于 HTTPS 请求(注意它的值通常仍然写成 http:// 开头,因为那是到代理服务器的连接协议),all_proxy 是不少工具支持的通配设置,常用来指向 SOCKS5 端口。很多工具只认其中一两个,所以通常三个一起设置最保险。另外部分工具只识别大写形式,建议大小写都设。
设了代理为什么访问公司内网也走代理了?
因为没有设置 no_proxy 例外列表。需要把 localhost、127.0.0.1、内网网段和公司域名加进 no_proxy,这些地址就会绕过代理直连。注意 no_proxy 的写法在不同工具间有差异,多数支持逗号分隔的域名后缀和 IP,但对 CIDR 网段的支持并不统一,必要时把关键网段逐段列出。
Docker 里 127.0.0.1 指向的是谁?
指向容器自己,不是宿主机。所以在容器内把代理写成 127.0.0.1 一定连不上。Linux 下用宿主机在 docker0 网桥上的地址或 host.docker.internal(需显式添加 host-gateway),macOS 和 Windows 的 Docker Desktop 直接支持 host.docker.internal。这是容器代理配置里最高频的错误。
调用 AI API 时为什么要固定出口节点?
因为 API 的风控比网页版严格得多。如果客户端用的是自动选择或负载均衡策略,每次请求的出口 IP 都可能不同,服务端会把这种模式判定为异常访问,轻则要求验证,重则暂停密钥。正确做法是在客户端为 API 域名写一条独立规则,指向一个固定的、原生 IP 的节点,不参与任何自动切换。
配置了代理后 npm install 报证书错误怎么办?
先确认错误来自哪一层。如果是自签名证书错误,常见原因是所在网络有 TLS 中间人设备,或者客户端开了 MITM/解密功能,应该关闭客户端的解密功能而不是关闭证书校验。永久性地关闭证书校验会让所有依赖下载失去完整性保证,属于危险操作,不要作为常规解法。企业环境下的正确做法是把公司根证书加入工具的信任链。
有没有办法不给每个工具单独配代理?
有,开客户端的 TUN 模式。TUN 在系统层面接管路由,所有走 IP 的流量都会经过规则判断,终端、Docker、构建工具全部自动覆盖,不需要任何环境变量。代价是需要管理员权限,且排查问题时多了一层。实际工作中常见的组合是:日常开 TUN,遇到需要精确控制某个工具时再叠加环境变量。

↑ 返回顶部