下面的内容完全是 AI 大模型生成的,与本人毫无关系,本人不对内容负任何责任。

代理的基本概念

代理的核心作用是:将应用发起的网络请求交给中间服务器,由该服务器代替本机访问目标地址。

理解代理需要从三个问题入手:

  • 流量如何进入代理(接管方式)
  • 应用如何决定是否使用代理
  • 代理使用什么协议进行转发

系统如何支持代理

操作系统本身并不会自动代理所有流量,而是提供若干机制,使应用可以选择使用代理。

环境变量

常见形式:

1
2
3
4
5
6
7
8
9
http_proxy=...
https_proxy=...
all_proxy=...
no_proxy=...

HTTP_PROXY=...
HTTPS_PROXY=...
ALL_PROXY=...
NO_PROXY=...

各个变量的含义如下表

变量 含义
http_proxy HTTP 请求所使用的代理
https_proxy HTTPS 请求所使用的代理
all_proxy 通用使用的代理(兜底)
no_proxy 指定不走代理,直接连接的地址(通常是本地地址)

Linux 设置相关环境变量

1
2
3
4
5
6
7
8
9
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export all_proxy=socks5h://127.0.0.1:7891
export no_proxy=localhost,127.0.0.1

export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
export ALL_PROXY="$all_proxy"
export NO_PROXY="$no_proxy"

撤销相关环境变量

1
2
unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY

Windows 设置相关环境变量

1
2
3
$env:http_proxy="http://127.0.0.1:7890"
$env:https_proxy="http://127.0.0.1:7890"
...

撤销相关环境变量

1
2
3
$env:http_proxy=""
$env:https_proxy=""
...

特点:

  • 应用主动读取这些变量
  • 应用决定是否使用代理
  • 不属于系统强制行为

注:

  • 这里的 http_proxy 等指的是 http 请求希望走的代理 URL,并没有要求代理类型,实际上代理类型可以是 http 代理,也可以是 socks5 代理。
  • 不同应用支持的变量也不一样(例如 curl 通常支持 all_proxy;wget 更常用 http_proxyhttps_proxy,对 all_proxy 的支持并不统一。),有的系统和应用会区分环境变量大小写,虽然大部分使用小写版本的,但是最好都提供
  • Windows 通常不区分环境变量的大小写

系统代理(System Proxy)

有的操作系统提供了统一代理配置接口,可以在系统设置中找到,例如:

  • Windows 系统代理(控制面板 → 代理设置)
  • macOS 网络代理

特点:

  • 提供全局代理配置
  • 应用可以选择是否使用
  • 对图形界面程序友好
  • 很多命令行工具都不会系统代理(例如 curlwgetgit 等),它们更倾向于通过环境变量设置代理。
  • 系统代理通常主要服务于 HTTP/HTTPS 流量;部分系统或应用也支持 SOCKS 代理,但是否生效取决于应用是否读取系统代理配置。

注意:Linux 并没有准备统一的系统代理,而且即使桌面环境准备了系统代理,绝大部分 CLI 工具也通常不会使用。

透明代理(网络层接管)

通过网络层机制拦截流量,例如:

  • 路由表修改
  • 防火墙规则(如 NAT / 重定向)
  • 虚拟网卡(TUN)

特点:

  • 应用无感知
  • 可接管绝大部分经过系统网络栈的流量
  • 不依赖应用支持
  • 配置复杂,调试困难

代理协议

代理不仅是“一个端口”,还涉及通信协议,常见代理协议包括 HTTP 代理和 SOCKS5 代理。

HTTP 代理

形式:

1
http://host:port

原理:

  • 工作在应用层
  • 理解 HTTP 请求结构,支持 HTTP 请求,以及通过 CONNECT 方法为 HTTPS 建立隧道

特点

  • 广泛支持,配置简单
  • 主要用于 HTTP/HTTPS 请求

注意:通常写 http:// 而不是 https://,写成 http:// 并不影响代理访问的安全性,而且大多数代理软件不支持写成 https:// 的形式。

SOCKS5 代理

形式:

1
2
socks5://host:port
socks5h://host:port

原理:

  • 工作在传输层
  • 不解析协议内容
  • 转发任意 TCP 连接,并在协议层支持 UDP 转发(需客户端配合)
  • 支持 SSH(HTTP 代理也可以通过 CONNECT 支持 SSH,但通常需要额外配置 ProxyCommand)

特点:

  • 支持任意协议
  • 更通用
  • 可避免本地 DNS 解析问题
  • 需要客户端支持

注意:socks5://socks5h:// 的区别在于哪一方负责解析域名:socks5:// 是本地解析,socks5h:// 是代理端解析。

代理端口

代理服务通常通过不同的端口提供不同协议入口。

典型划分如下:

1
2
3
端口 A → HTTP 代理
端口 B → SOCKS5 代理
端口 C → 透明代理

例如

1
2
3
4
5
6
7
8
# HTTP 代理端口
port: 7890

# SOCKS5 代理端口
socks-port: 7891

# Linux 和 macOS 的 redir 代理端口
redir-port: 7892

HTTP 和 SOCKS 代理对应的 URL 分别为

1
2
3
4
http://127.0.0.1:7890

socks5://127.0.0.1:7891
socks5h://127.0.0.1:7891

这里不能把端口和协议错位使用。

某些代理服务会选择使用混合端口(Mixed Port):

1
单一端口 → 同时支持 HTTP 和 SOCKS

例如

1
2
# HTTP 和 SOCKS5 混合代理端口
mixed-port: 7890

特点:

  • 自动识别协议
  • 使用简单

关于混合端口的补充:

  • 对于客户端来说,使用代理的方式由 URL 前缀直接确定;
  • 对于代理端来说,它只是在监听一个端口,需要根据实际内容进一步判断应该使用 http 还是 socks5 代理。
  • 混合端口的自动识别依赖实现细节,在一般场景下简单方便,但是在复杂场景下可能不如端口分离的方案稳定可靠。

小结

代理可以抽象为三层:

1
2
3
4
5
6
7
8
[应用层]
是否使用代理(显式 / 环境变量 / 系统设置)

[协议层]
使用 HTTP 代理还是 SOCKS5 代理(层次不同,支持的范围也不同)

[网络层]
是否被强制接管(透明代理)

命令行工具使用代理

下面假设本地代理监听的端口为

1
2
3
4
5
# HTTP 代理端口
port: 7890

# SOCKS5 代理端口
socks-port: 7891

如果使用 mixed-port,那么 HTTP 代理端口和 SOCKS5 代理端口一致。

curl

curl 支持多种代理协议,可以通过命令行参数或环境变量进行设置。

命令行参数指定 HTTP 代理或 SOCKS5 代理

1
2
3
curl -x http://127.0.0.1:7890 https://example.com

curl -x socks5h://127.0.0.1:7891 https://example.com

通过环境变量设置代理例如

1
2
3
http_proxy=http://127.0.0.1:7890 \
https_proxy=http://127.0.0.1:7890 \
curl https://example.com

wget

wget 主要支持 HTTP / HTTPS 代理。

命令行参数指定 HTTP 代理

1
wget -e http_proxy=http://127.0.0.1:7890 https://example.com

通过环境变量设置代理例如

1
2
3
http_proxy=http://127.0.0.1:7890 \
https_proxy=http://127.0.0.1:7890 \
wget https://example.com

ProxyChains

proxychains-ng 是一个代理辅助工具,用于强制让一些不支持代理的程序走代理
原理是通过 hook 系统调用(如 connect),拦截网络连接并重定向到代理

安装后修改配置文件:

1
/etc/proxychains4.conf

或用户级配置文件

1
~/.proxychains/proxychains.conf

配置文件中需要修改内容例如:指定 SOCKS5 代理

1
2
[ProxyList]
socks5 127.0.0.1 7891

使用例如

1
proxychains4 curl https://example.com

加上 -q 开启静默模式,避免对 stdout 造成干扰。

1
proxychains4 -q curl https://example.com

注意:

  • 不要和环境变量 http_proxy 等混用,可能导致代理叠加或行为不确定
  • 不适用于所有程序,因为采用 hook 机制,对部分程序(静态链接 / 特殊网络实现)可能无法生效

关于 Github 的访问 & git 使用代理

现在关注在 git 命令中如何使用代理,实际需求就是如何稳定访问 Github 的问题。由于 git 远程仓库的链接包括 http(s) 和 ssh 两类,因此也需要考虑对应情景下如何使用代理。

在大部分情况下直连 Github 是可以的,但是偶尔会出现连接超时,无法推送和拉取 Github 仓库,有很多种解决办法,原理各不相同,而且都无法保证奏效。

解决方案可以分为两类:

  • 第一类方案不需要本地代理;
  • 第二类方案则依赖本地代理。

参考:一文让你了解如何为 Git 设置代理

不依赖本地代理

SSH 跳板机 / ProxyCommand 转发

可以基于 SSH 跳板机 / ProxyCommand 转发功能,用一个网络状态更好的,可以访问 Github 的服务器作为中转站,配置例如

1
2
3
4
5
6
Host B
...

Host github.com
User git
ProxyCommand ssh -q -W %h:%p B

这段配置有很多等价或有细微差异的现代写法,但是这里没有采用。

可以用下面的方式进行临时使用

1
2
3
GIT_SSH_COMMAND='ssh -o ProxyCommand="ssh -q -W %h:%p B"' git clone git@github.com:OWNER/REPO.git
GIT_SSH_COMMAND='ssh -o ProxyCommand="ssh -q -W %h:%p B"' git fetch
GIT_SSH_COMMAND='ssh -o ProxyCommand="ssh -q -W %h:%p B"' git push

ssh.github.com

Github 官方支持使用 ssh.github.com 代替 github.com,这会把 ssh 连接端口从 22 改到 443,在某些情况下会好很多(参考官方文档)。

可以修改 git 远程仓库的 URL,但是更建议在 .ssh/config 中直接覆盖修改

1
2
3
4
Host github.com
User git
Port 443
HostName ssh.github.com

可以用下面的方式进行临时使用

1
GIT_SSH_COMMAND='ssh -o HostName=ssh.github.com -p 443' git clone git@github.com:OWNER/REPO.git

可以将代理转发和 ssh.github.com 结合,得到如下的配置方案

1
2
3
4
5
6
7
8
Host B
...

Host github.com
User git
Port 443
HostName ssh.github.com
ProxyCommand ssh -q -W %h:%p B

依赖本地代理

假设本地代理监听的端口为

1
2
3
4
5
# HTTP 代理端口
port: 7890

# SOCKS5 代理端口
socks-port: 7891

如果使用 mixed-port,那么 HTTP 代理端口和 SOCKS5 代理端口一致。

下面不按照代理协议进行区分,而是按照使用 http(s) 链接或 ssh 链接的远程仓库,分别进行代理配置。

http(s) 链接

对于使用 http(s) 链接的远程仓库,Git 提供了 http.proxy 配置项,用于 http(s) 请求的代理配置。

添加 http 代理(默认仓库级配置,加上 --global 则全局生效)

1
git config http.proxy http://127.0.0.1:7890

还可以添加 socks5 代理

1
git config http.proxy socks5h://127.0.0.1:7891

这看起来有点奇怪,http.proxy 为什么可以指定 socks5 代理?因为 http.proxy 的语义是用于 HTTP 请求的代理配置,并不是 HTTP 类型的代理。

可以用下面的方式进行临时使用

1
2
3
4
5
git -c http.proxy=http://127.0.0.1:7890 \
clone https://github.com/OWNER/REPO.git

git -c http.proxy=socks5h://127.0.0.1:7891 \
clone https://github.com/OWNER/REPO.git

或者通过环境变量进行设置

1
2
3
http_proxy=http://127.0.0.1:7890 \
https_proxy=http://127.0.0.1:7890 \
git clone https://github.com/OWNER/REPO.git

可以用下面的命令撤销(加上 --global 撤销全局配置)

1
git config --unset http.proxy

ssh 链接

对于使用 ssh 链接的远程仓库,代理配置需要针对 ssh 自身进行。

使用 http 代理例如

1
2
3
4
5
6
7
8
9
# windows
Host github.com
User git
ProxyCommand connect -H 127.0.0.1:7890 %h %p

# linux
Host github.com
User git
ProxyCommand nc --proxy 127.0.0.1:7890 --proxy-type http %h %p

使用 socks5 代理例如

1
2
3
4
5
6
7
8
9
# windows
Host github.com
User git
ProxyCommand connect -S 127.0.0.1:7891 %h %p

# linux
Host github.com
User git
ProxyCommand nc -X 5 -x 127.0.0.1:7891 %h %p

对应的一次性命令例如

1
2
GIT_SSH_COMMAND='ssh -o ProxyCommand="nc -X 5 -x 127.0.0.1:7891 %h %p"' \
git clone git@github.com:OWNER/REPO.git