第 4 章
网络代理搭建
问题与场景
考虑这样一个场景:我有一台 Win11 主机能够访问 GitHub,但我在另一台 Ubuntu 服务器上进行开发,直连 GitHub 经常超时,git clone 根本跑不动。我可以把 Win11 的网络能力共享给这台服务器吗?如果有多台服务器都需要呢?我们通过搭建网络代理来解决这个问题。
梳理一下问题场景,现在有:
- 一台 Win11 主机(192.168.31.2),能访问 GitHub;
- 一台 Ubuntu 服务器(192.168.31.98),不能访问 GitHub。
需要让这台 Ubuntu 服务器连上 GitHub!
最直接的想法是让 Ubuntu 服务器直接走 Win11 主机的网络。但如果有多台服务器都需要代理呢?我需要一个统一的代理入口!大家都知道,在 Linux 上配置代理服务(比如 Squid)比 Windows 方便得多,因此我用 VMWare 创建了一台 Ubuntu 虚拟机,名为 Kirara(192.168.31.125),专门做流量中转。
另外,我不想让代理跑在日常工作的 Win11 主机上 —— 代理客户端喜欢接管系统网络设置,容易跟其他软件冲突。所以我又创建了一台 Win11 虚拟机(192.168.31.3),专门跑代理,跟工作环境隔离开。
总之,现在我们有了能稳定访问 GitHub 的 Win11 虚拟机(192.168.31.3),以及一台准备作为统一代理入口的 Ubuntu 虚拟机 —— Kirara(192.168.31.125),然后我们开始搭建整个网络代理框架,如下图所示。

第一层:Ubuntu 服务器的代理开关
首先来到 Ubuntu 服务器(192.168.31.98),它需要有方便的代理开关。因此,我做了 proxyon、proxyoff 和 proxystat 三个自定义命令,就像三个小按钮,放在我的家目录中。
# ~/.proxy.d/proxy-onoff.sh
PROXY_URL="http://192.168.31.125:8888"
proxyon() {
export http_proxy="$PROXY_URL"
export https_proxy="$PROXY_URL"
export ftp_proxy="$PROXY_URL"
export no_proxy="localhost,127.0.0.1,192.168.31.0/24"
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
export FTP_PROXY="$ftp_proxy"
export NO_PROXY="$no_proxy"
echo "[proxy] ON -> $PROXY_URL"
}
proxyoff() {
unset http_proxy https_proxy ftp_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY
echo "[proxy] OFF"
}
proxystat() {
echo "http_proxy=${http_proxy:-<empty>}"
echo "https_proxy=${https_proxy:-<empty>}"
echo "no_proxy=${no_proxy:-<empty>}"
}
配置的是连接到 Kirara(192.168.31.125)的 8888 端口,我把这个脚本设置为开机自动加载。
# 将脚本设置为开机自动加载
source ~/.proxy.d/proxy-onoff.sh
# 也可以用下面这个,首先检查脚本文件是否存在,更严谨
[[ -f ~/.proxy.d/proxy-onoff.sh ]] && source ~/.proxy.d/proxy-onoff.sh
现在,Ubuntu 服务器(192.168.31.98)上的代理开关就做好了!之后终端里敲 proxyon 就能开代理,敲 proxyoff 就能关掉。值得注意的是,这个脚本操作的是 http_proxy 环境变量,而 http_proxy 环境变量只对读取它的程序有效。因此,有些程序在使用代理时可能需要显式参数或额外配置,例如 docker。
第二层:Kirara 的 Squid 代理
第二步,我们继续配置 Kirara。需要安装 Squid,然后修改默认配置文件 /etc/squid/squid.conf,在这个文件中配置好 Squid 代理服务的访问控制策略,即 ACL(访问控制列表)。
sudo apt install squid
主要思路包括:
- Squid 监听 8888 端口。
- ACL 维护一个可以连接代理的白名单,只允许局域网或本地设备接入,拒绝其他来源的访问。
- Squid 接受到的所有请求,都交给本机(127.0.0.1)的 3128 端口,通过 SSH 隧道转发给上游代理。
# /etc/squid/squid.conf,配置文件部分内容
# 监听所有接口的 8888 端口
http_port 8888
# ACL:只允许内网设备连入
acl localnet src 192.168.31.0/24
http_access allow localnet
http_access deny all
# 所有请求转发给上游代理(SSH 隧道)
cache_peer 127.0.0.1 parent 3128 0 no-query default
never_direct allow all
与代理开关一样,Squid 进程和 SSH 隧道也需要持久化,让它们随时可用。其中,Squid 通过 apt 安装后自带 systemd 服务,天然开机自启,而 SSH 隧道需要手动创建一个 systemd service。这个 SSH 隧道服务的核心是 ssh -L 3128:127.0.0.1:7890 -N yustia@192.168.31.3,配合 Restart=always 实现断线自动重连,将 Kirara 的 3128 端口连接到 Win11 虚拟机的 7890 端口。
# /etc/systemd/system/ssh-tunnel.service
[Unit]
Description=SSH Tunnel to Win11 VM Privoxy
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=user
ExecStart=/usr/bin/ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -L 3128:127.0.0.1:7890 -N yustia@192.168.31.3
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
第三层:Win11 虚拟机出口
最后,第三层的 Win11 虚拟机是整条链路的出口,已经有一个监听 7890 端口的代理服务(Privoxy)在运行。这个服务进程接收 SSH 隧道传来的流量并转发出去,至于这个代理服务如何实现、上游接到哪,因人而异,不在本文讨论范围内,但这里提供的端口和网络访问能力可以统一!
结果验证
$ # 在Ubuntu服务器(192.168.31.98)上
$ curl -x http://192.168.31.125:8888 https://github.com -I
HTTP/1.1 200 Connection established
至此,网络代理搭建完成,Ubuntu 服务器可以通过 Kirara 访问 GitHub 了。
留言区待配置
部署 Twikoo 后端后,设置环境变量 NEXT_PUBLIC_TWIKOO_ENV_ID