注意
以下内容通过 AI 整理汇总。
最近我遇到了一个看似简单,但实际上颇为棘手的网络问题。事情是这样的:
我在国内工作,手上有一个海外的HTTP代理服务,格式是 http://username:password@proxy.example.com:31212
。由于众所周知的原因,这个代理在国内是直接访问不了的。不过,我还有一台位于海外的VPS服务器(IP:x.x.x.x),国内是可以正常访问的。
我的想法很简单:既然我能访问海外VPS,VPS能访问代理,那我就在VPS上搭建一个转发服务,让流量走这样的路径:
本地电脑(中国) → 海外VPS → HTTP代理 → 目标网站
听起来是不是很合理?我当时也是这么想的。
首先,我SSH登录到海外VPS上,写了个简单的Python脚本测试代理是否正常:
pythonimport asyncio
import aiohttp
async def test_proxy():
proxy = "http://username:password@proxy.example.com:31212"
async with aiohttp.ClientSession() as session:
async with session.get(
url="http://www.google.com",
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
},
proxy=proxy,
) as response:
print(f"Status: {response.status}")
print(f"Response length: {len(await response.text())}")
asyncio.run(test_proxy())
运行结果:完全正常!代理是可用的。
接下来,我尝试了多种转发方案:
然而,奇怪的事情发生了...
当我在本地通过这些转发服务访问时,全部失败!错误信息都是:
Connection reset by peer
更诡异的是,我发现了一个规律:
这就很奇怪了。按理说,如果是转发服务的问题,那应该一直都不能用才对。为什么使用了透明代理就能工作呢?
经过一番思考和查阅资料,我终于明白了问题所在:GFW的深度包检测(DPI)。
当我们从国内直接访问海外服务器时,所有的数据包都会经过GFW。GFW不仅仅是简单地封锁IP或域名,它还会进行深度包检测,分析数据包的内容和模式。
对于HTTP代理来说,有几个明显的特征:
Proxy-Authorization
等当GFW检测到这些特征时,它会认为这是一个代理连接,然后主动发送RST包来断开连接。这就是为什么我们会收到"Connection reset by peer"的错误。
当使用Shadowsocks等透明代理时,我们的流量已经被加密和混淆了。GFW看到的只是一堆加密数据,无法识别出里面包含的HTTP代理协议特征,所以就不会干扰连接。
这就像是:
在尝试了各种复杂的转发方案后,我意识到:与其在应用层做各种转发和伪装,不如直接在网络层解决问题。
最终我采用了一个简单粗暴但非常有效的方案:
直接在海外VPS上使用 sing-box 搭建了一个 VLESS 节点。sing-box 是一个强大的网络代理平台,支持多种协议,而 VLESS 是一个轻量级的代理协议,具有良好的性能和安全性。
配置非常简单,sing-box 可以直接配置上游代理,这样就形成了:
本地 → VLESS加密隧道 → VPS上的sing-box → HTTP代理 → 目标网站
在本地电脑上,我使用 Clash 配置了 VLESS 节点,并开启了 TUN 模式。TUN 模式是一种透明代理模式,它会在系统层面创建一个虚拟网卡,所有的网络流量都会经过这个虚拟网卡。
这样做的好处是:
配置好之后,我的Python代码可以直接这样写:
pythonimport aiohttp
import asyncio
async def fetch_youtube():
# 直接用代理,clash 已经接管了系统流量,会自动绕到中转节点的。
proxy = "http://user:passj@proxy.example.com:31212"
async with aiohttp.ClientSession() as session:
async with session.get("https://www.youtube.com",proxy=proxy) as response:
print(f"Status: {response.status}")
print(f"Title found: {'YouTube' in await response.text()}")
asyncio.run(fetch_youtube())
SSH是一个非常常见的服务器管理协议,不容易被封锁。我们可以利用SSH的端口转发功能:
在VPS上运行HTTP转发服务(监听本地端口) 在本地建立SSH隧道:
bashssh -N -L 8080:localhost:8888 root@your-vps-ip
这样,访问本地的8080端口就相当于访问VPS上的8888端口,而且所有流量都是通过SSH加密的。
使用专业的工具,进行加密隧道转发。
国内的网络是没有 gfw 的,如果我有多台中转服务器,就是想在代码里精确控制,灵活搭配,而且还得用 http 代理。
那么可以找一个国内的中转服务器,与国外的若干个中转服务器组成加密隧道或者 vps(wireguard、tailscale、gost 等),然后在国内搭建 http 代理转发,流量在国内的中转节点加密后到国外的中转节点,然后再到海外的代理服务器。
这次经历让我深刻理解了几个道理:
最重要的是,这个方案让我可以专注于业务逻辑,而不是纠结于网络问题。代码该怎么写就怎么写,就像没有任何网络限制一样。
有时候,最简单的方案反而是最好的方案。与其绕来绕去,不如一步到位!
本文作者:mereith
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!