一、背景

也算是知道了为啥好多人建站不选阿里云、腾讯云这类大陆云服务大厂,而是选择一些不知名小厂,然后把服务器设在香港的原因……之一。可以免除备案与审查之苦是一方面,但真正重要的是——终于可以顺畅地从github、npm(等)海外源下东西了!

然而我在配服务器前没想到这一点 (悲😭) ,因此在经历一次又一次 Connection failed 和本地下包手动上传之后,我自然而然地把小算盘打向了运行在本地Windows系统的VPN(客户端:FlClash)。虽然不太清楚VPN客户端具体的运行方式,然而在基本设置中略微找寻就发现了 端口号 7890 ,因此大概得以明白基本逻辑:

info:使用“系统代理”模式(而非虚拟网卡)运行在本地的VPN客户端在启动后,会开启一个后台进程监听本地的一个端口(对于FlClash,这个端口是7890),同时修改Windows系统代理(将其配置为 127.0.0.1:7890)。所有支持代理的应用(例如浏览器)将流量发送到VPN客户端,客户端依据“规则”,判断流量是否走海外代理

FlClash的设置页面:端口为7890FlClash的设置页面:端口为7890

这样一来,思路就很清晰了。由于我一直用SSH连接我的服务器,因此,我们需要的就是

  1. 服务器端:开辟一个端口,利用 http-proxy https-proxy 代理配置,将所有系统流量发送到这个端口。
  2. 利用本地与云服务器之间已经建立的 SSH 加密通道,将云服务器发送到此前开辟的端口的流量“逆流”传回本地电脑的代理软件上。(学名:SSH反向隧道

二、具体实现

Step1. 本地

首先打开VPN客户端确定端口号(7890 for me),并勾选允许局域网代理。然后想好你要在服务器端使用的监听端口(随便,为了便于区分,我选择和本地保持一致,也即是7890)。最后建立SSH反向隧道,使用-R参数,一行命令即可搞定:

# 命令格式:ssh -R [服务器监听端口]:127.0.0.1:[本地代理端口] 用户名@服务器IP
ssh -R 7890:127.0.0.1:7890 root@你的服务器IP

为了一劳永逸,可以把它写进Windows SSH配置文件(它是 "$env:USERPROFILE\.ssh\config" ),譬如这样:

Host myserver_vpn_7890
    HostName 12.34.56.789
    User root
    IdentityFile ~/.ssh/my_private_key
    IdentitiesOnly yes
    Port 22
    RemoteForward 7890 127.0.0.1:7890 # <--

这样以后就只用 ssh myserver_vpn_7890 即可。

Step2. 服务器端

登录后配置 http-proxy https-proxy 代理:

export http_proxy=http://127.0.0.1:7890 && export https_proxy=http://127.0.0.1:7890

检查一下:

curl -I https://github.com

出现200响应即连接成功!

只要不断开与这个终端窗口的SSH连接,VPN代理就一直有效。为了偷懒,可以把代理配置的命令 alias.bashrc or .zshrc 里面(我是这么干的:alias myvpn='export http_proxy=http://127.0.0.1:7890 && export https_proxy=http://127.0.0.1:7890'

info:Tip:如果你使用tmux等终端复用器,记得你需要在每个你要进行海外地址下载操作的终端窗口都配置一次 http-proxy https-proxy 代理。这也是为什么 alias 这么香的原因🙂。

一个常见的坑

——就是在建立SSH反向隧道连接服务器后进行了操作但并未登出而是直接关掉了终端窗口 ,又再次想要建立SSH反向隧道连接服务器:这种情况下,新开的会话是无法成功建立7890端口的反向隧道的(因为还被上一个会话占用着)。解决方案是首先检查哪个进程目前还占用着这个端口:

> lsof -i :7890
# 示例输出
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
sshd    37581 root    5u  IPv6 1388816      0t0  TCP ip6-localhost:7890 (LISTEN)
sshd    37581 root    7u  IPv4 1388817      0t0  TCP localhost:7890 (LISTEN)

kill -9 [PID] 杀掉这些进程,登出,再建立SSH反向隧道连接服务器并配置 http-proxy https-proxy 即可解决。