# 在 curl 中使用代理：-x、环境变量、SOCKS5 与认证

Source: https://ipvolt.com/zh/guides/curl-proxy-setup
Markdown: https://ipvolt.com/zh/guides/curl-proxy-setup.md
Language: zh-CN

[ipvolt 首页](https://ipvolt.com/zh.md) / [指南](https://ipvolt.com/zh/guides.md) / 在 curl 中使用代理：-x、环境变量、SOCKS5 与认证

集成
审校于: 2026-09-17
阅读约 7 分钟
作者： ipvolt

如何在 curl 中使用代理：-x 参数、http_proxy 与 https_proxy 变量、通过 socks5h 使用 SOCKS5、代理认证，以及如何解读 CONNECT 与 407 错误。

## 起点

curl 选择代理的每一种方式：从单个 -x 参数到环境变量，以及决定请求能否成功的认证、SOCKS5 和隧道细节。

## 用 -x 为单个请求设置代理

-x 选项（长形式写作 --proxy）将单个 curl 请求经由代理转发。传给它代理的协议、主机和端口。省略协议时 curl 默认使用 http://，省略端口时默认使用 1080，因此两者都应显式写出。

协议描述的是到代理的连接，而不是目标站点。经普通 HTTP 代理访问 https:// 目标时仍然使用 -x http://host:port；curl 会通过它打开一条 CONNECT 隧道。只有当提供商在代理本身终止 TLS 时才写 -x https://host:port。curl 在此处还接受 socks4://、socks4a://、socks5:// 和 socks5h://。

下面的命令沿用了本指南其余部分的两个习惯：--disable 忽略可能自行添加代理的 curlrc，--noproxy '' 取消任何继承来的 no_proxy 排除项，确保请求真正经过你指定的网关。proxy.example.invalid 是刻意无法解析的；请替换为你提供商的网关。

### curl -x · 经代理发送一个请求

```sh
curl --disable --noproxy '' \
  -x http://proxy.example.invalid:8080 \
  https://example.com/
```

## 代理认证：-U、--proxy-user 与 407

代理凭据与目标站点凭据是分开的。-U 或 --proxy-user 把凭据发给代理；-u 或 --user 把凭据发给目标站点。两者混用会导致代理返回 407 或目标站点返回 401，即使密码本身是正确的。

你也可以把凭据嵌入代理 URL，写成 http://user:password@host:port。先对保留字符做百分号编码：密码中的 @ 必须写成 %40，否则 curl 会把它当作主机部分的开始。Basic 是默认的代理认证方案；当提供商有文档说明时，可用 --proxy-digest、--proxy-ntlm 和 --proxy-anyauth 选择其他方案。

这两种形式都会把密码放进进程参数列表和 shell 历史。应改为从变量读取，或使用下面诊断脚本中展示的 curl 8.3 的 --variable 与 --expand-proxy-user 形式，它在导入密钥时不会将其暴露为参数。

- connect=407 或消息 Received HTTP code 407 from proxy after CONNECT 表示代理拒绝了凭据或根本没有收到凭据。检查 -U 的值、编码以及提供商的用户名格式。
- 隧道已成功但目标站点返回 401，属于目标站点的问题；代理这一步已经正常工作。
- 许多提供商把国家、会话或协议选项编码在用户名中。严格遵循提供商文档中的格式；curl 会原样传递该字符串。

### curl --proxy-user · 从环境变量读取凭据

```sh
: "${PROXY_USERNAME:?}" "${PROXY_PASSWORD:?}"
curl --disable --noproxy '' \
  -x http://proxy.example.invalid:8080 \
  --proxy-user "$PROXY_USERNAME:$PROXY_PASSWORD" \
  https://example.com/
```

## 环境变量：http_proxy、https_proxy、no_proxy 与 .curlrc

不带 -x 时，curl 会在环境中查找代理。它只读取小写的 http_proxy，因为大写名称可能被 CGI 请求头设置；它接受 https_proxy 或 HTTPS_PROXY、all_proxy 或 ALL_PROXY，以及 no_proxy 或 NO_PROXY。变量按目标站点的协议选择：https:// 目标使用 https_proxy，因此只导出 http_proxy 会让 HTTPS 流量继续直连。

no_proxy 是以逗号分隔的主机名或域名后缀列表，其中的条目绕过代理；单独一个 * 则完全禁用代理。命令行上的 -x 始终优先于环境变量，命令行上的 --noproxy 始终优先于 no_proxy。

~/.curlrc 文件可以通过 proxy = "http://host:port" 为每次调用设置代理，这在工作站上很方便，但在容器或 CI 任务里会令人意外。当脚本必须忽略它时，运行 curl 时把 --disable（或其短形式 -q）作为第一个参数。

### http_proxy 与 https_proxy · shell 会话

```sh
export http_proxy='http://proxy.example.invalid:8080'
export https_proxy='http://proxy.example.invalid:8080'
export no_proxy='localhost,127.0.0.1,.internal.example'
curl https://example.com/         # uses https_proxy
curl --noproxy '*' https://example.com/   # bypasses the proxy once
```

## 在 curl 中使用 SOCKS5：socks5 与 socks5h 的区别

curl 通过同一个 -x 选项使用 SOCKS。socks5:// 在你的机器上解析目标主机名，并向代理发送 IP 地址。socks5h:// 发送主机名并让代理解析，当目标必须从代理所在网络解析、或本地 DNS 完全不应看到目标时，这正是你需要的。长选项 --socks5 和 --socks5-hostname 与之等价。

SOCKS5 的用户名密码认证使用同一个 --proxy-user 选项。SOCKS 没有 CONNECT 状态码，因此握手被拒绝时表现为 curl 退出码 97 并附带简短原因，而不是 407。

### curl socks5h · 代理侧 DNS

```sh
curl --disable --noproxy '' \
  -x socks5h://proxy.example.invalid:1080 \
  --proxy-user "$PROXY_USERNAME:$PROXY_PASSWORD" \
  https://example.com/
```

## HTTPS 目标：CONNECT 隧道与 -v

经 HTTP 代理访问 https:// 目标时，curl 首先向代理发送 CONNECT example.com:443。只有在代理回应 200 之后，curl 才在隧道内与目标站点开始 TLS，因此代理永远看不到解密后的请求。加上 -v 运行可以观察这两个步骤；CONNECT 响应在任何目标站点响应头之前到达。-p 或 --proxytunnel 会对普通 http:// 目标强制使用同样的隧道。

对普通 http:// 目标则没有隧道。curl 把完整 URL 发给代理，由代理去获取，你看到的响应头可能来自任何一方。当需要把某个状态码归属到某一层时，优先使用隧道的情形，并用 %\{http_connect\} 输出变量单独读取 CONNECT 状态。

使用 https:// 代理时，curl 会同时验证代理和目标站点的证书。--proxy-cacert 为代理提供私有信任包；保持两项验证都开启，而不是求助于 --proxy-insecure 或 -k。

## 先发送一个有限制的请求作为基线

把下面的内容保存为 proxy-check.sh 并用 sh proxy-check.sh 运行。它需要 curl 8.3 或更高版本以及 HTTP Basic 代理认证。让你的密钥管理器填充 PROXY_USERNAME 和 PROXY_PASSWORD，并把 PROXY_URL 设为提供商网关（含协议和端口）；https://proxy.example.invalid:8443 是一个刻意无法连接的示例值。

curl 自行导入凭据，因此展开后的密码永远不会成为 shell 参数。该命令打印目标站点状态、CONNECT 状态和耗时，并丢弃响应体。在加入浏览器、并发或应用代码之前，先保留这个基线。

### proxy-check.sh · curl 8.3+

```sh
: "${PROXY_URL:?Set your provider proxy URL}"
curl --disable --silent --show-error --fail \
  --noproxy '' \
  --proxy "$PROXY_URL" \
  --variable %PROXY_USERNAME \
  --variable %PROXY_PASSWORD \
  --expand-proxy-user '{{PROXY_USERNAME}}:{{PROXY_PASSWORD}}' \
  --connect-timeout 10 --max-time 30 \
  --output /dev/null \
  --write-out 'http=%{http_code} connect=%{http_connect} seconds=%{time_total}\n' \
  'https://example.com/'
```

## 解读 curl 退出码并找出出问题的层

一次成功的响应只证明这个请求完成了；它并不能确定具体的出口国家或运营商。要确认这些，请使用提供商文档中的诊断端点，或你自己控制的、能报告观测到的源地址的端点。

在把你的应用与 curl 做对比时，保持相同的目标站点和凭据。一次改动三项设置，会让一次成功的重试难以解释。向支持人员提供退出码、耗时和脱敏后的状态，而不是包含认证数据的详细跟踪。

- 退出码 5，could not resolve proxy：网关主机名错误，或本地 DNS 无法解析它。
- 退出码 7，failed to connect：代理主机已解析，但端口关闭、被过滤或从本网络不可达。
- 退出码 28，operation timed out：先把 --connect-timeout 或 --max-time 调高一次以确认，再次出现则视为路由或容量问题。
- 退出码 56 且附带 Received HTTP code 407 from proxy after CONNECT：代理认证失败；先修正 -U，再去动目标站点的请求头。
- 退出码 97，proxy handshake error：SOCKS 握手被拒绝；检查 socks5 与 socks5h 协议的选择以及凭据。
- 退出码 35 或 60，TLS 失败：检查主机名、信任链和系统时钟。保持证书验证开启。

## 上线之前

- 使用提供商提供的真实网关，以及其文档中给出的协议和端口。
- 以私密方式注入凭据；不要把密钥粘贴进 shell 历史。
- 在测试并行流量之前，先记录一个有限制的基线。
- 在改动设置之前，先记下故障来自 CONNECT 步骤还是目标站点。

## 参考来源与延伸阅读

- [curl manual: -x, --proxy-user, --noproxy and write-out variables](https://curl.se/docs/manpage.html)
- [Everything curl: proxy environment variables](https://everything.curl.dev/usingcurl/proxies/env.html)
- [Everything curl: SOCKS proxies and hostname resolution](https://everything.curl.dev/usingcurl/proxies/socks.html)
- [Everything curl: proxy authentication](https://everything.curl.dev/usingcurl/proxies/auth.html)
- [Everything curl: separate proxy and destination connections](https://everything.curl.dev/transfers/conn/proxies.html)
- [libcurl error codes](https://curl.se/libcurl/c/libcurl-errors.html)

## 相关指南

- [不靠猜测修复代理错误 407](https://ipvolt.com/zh/guides/fix-proxy-error-407.md)
- [HTTP 与 SOCKS5 代理：按连接方式选择](https://ipvolt.com/zh/guides/http-vs-socks5-proxies.md)
- [代理环境变量：HTTP_PROXY 与 NO_PROXY](https://ipvolt.com/zh/guides/proxy-environment-variables.md)

## 关于 ipvolt

示例使用通用的代理设置，并附上原始技术文档链接。具体产品的行为请向你的服务商确认。ipvolt 仍在开发中。

[阅读英文原文](https://ipvolt.com/guides/curl-proxy-setup.md)

## 了解何时开放体验。

ipvolt · 开发中

我们正在为开发者和数据团队打造代理基础设施。加入意向名单，ipvolt 就绪时第一时间收到通知。

开放体验时仅发一封通知邮件，不发送其他邮件。

[申请抢先体验](https://ipvolt.com/zh/guides/curl-proxy-setup#waitlist-closing)

[隐私政策](https://ipvolt.com/privacy)

