一直以来都有做一个节点池的想法,但手上的项目没有一个能用上的,一直在 Todo List 中吃灰。最近在微信水群的时候,发现有需求,于是乎就快速搭建了一个节点池。
IPv4 节点池
使用的软件有:
Loading graph...
graph LR Client[客户端] --> | WebSocket | CF[Cloudflare] subgraph 前置代理 CF[Cloudflare] --> GOST end GOST --> | socks5 | Clash[Clash Meta] Clash[Clash Meta] --> 代理节点
核心是 Clash Meta,功能是管理代理节点池以及分流策略。
节点池是网上爬取的节点,然后在 Clash 配置文件中使用 proxy-providers
特性(就是 URL 订阅)获取节点。
策略使用的是负载均衡,通过创建一个负载均衡的规则,包括所有的节点,并设置为默认规则。可以参考我的配置:
proxy-groups:
- {
name: LB,
type: load-balance,
strategy: round-robin, # 将会把所有的请求分配给策略组内不同的代理节点
include-all-providers: true, # 包含所有的订阅节点
interval: 30,
lazy: false,
timeout: 10,
tolerance: 10,
}
rules:
- MATCH,LB
这套方案还使用了前置代理,原因是我直接用家宽轮询各节点发请求一段时间后,似乎被 ISP 盯上了,许多节点掉线,以及没法访问自己在国外的 VPS(停掉请求后一段时间恢复了)。于是做个前置代理,让海外的 VPS 来分流。 用 Gost 做前置代理,利用 Cloudflare 代理 Websocket,可以优化线路(我这台 VPS 线路比较差),且避免 IP 被墙(或者复活被墙的 IP),建议参考 lewang 的推特帖子。
VPS 启动 gost 命令行如下,后面的 -F 指把请求转发到 Clash(假设 Clash 监听的是 7890)。
gost -L wss://username:password@:443 -F socks5://localhost:7890
在本地也起一个 gost,监听本机的 8080 端口,然后转发到 VPS 上。本机后续只要设置代理到 127.0.0.1:8080
即可。
gost -L :8080 -F wss://username:password@your-vps-domain:443
IPv6 节点池
从网上爬得节点,大部分都是 IPv4 的。偶尔有些网站会支持 IPv6,那就把 IPv6 的节点池也弄上了。
这章节主要参考了 zu1k 的文章:https://zu1k.com/posts/tutorials/http-proxy-ipv6-pool/ ,不太一样是我用的是 He.net 的 IPv6。
首先是从 He.net 申请了一段 ipv6,具体可以参考:https://p3terx.com/archives/use-he-tunnel-broker-to-add-public-network-ipv6-support-to-ipv4-vps-for-free.html
在 He.net 申请 ipv6 后,可以在隧道页面上切换到 Example Configurations 根据发行版查询如何在系统上配置隧道。
把隧道跑起来后,机器就有了 he.net 提供的 ipv6 了。假设拿到的子网是 2001:fff:ff:ff::/64
。下一步是添加一条路由,其中 he-ipv6 是隧道设备名(如果你是按照官网的 Example Configurations 来配置的话,默认是这个名字)。
ip route add local 2001:fff:ff:ff::/64 dev he-ipv6
启动 ip_nonlocal_bind 特性,允许程序绑定本机不存在的 IP
sysctl -w net.ipv6.ip_nonlocal_bind=1
# 持久化
echo net.ipv6.ip_nonlocal_bind=1 >> /etc/sysctl.conf
而后使用 http-proxy-ipv6-pool 做代理,其作用是运行一个 HTTP 代理服务器,对于每次传入的请求都采用不同的 ipv6 发送出去。
http-proxy-ipv6-pool 是 rust 项目,由于 VPS 性能较弱,就没有在上面编译。在本地编译后传上去发现有 GLIBC 错误。后面采用静态编译就解决了(Musl),使用下面命令行:
cargo build --target x86_64-unknown-linux-musl --release
同样,使用 Gost 做一个前置代理,把链路连接起来:
服务端:
http-proxy-ipv6-pool -b 127.0.0.1:51080 -i 2001:fff:ff:ff::/64
gost -L wss://username:password@:8443 -F http://127.0.0.1:51080
客户端:
gost -L :8080 -F wss://username:password@your-vps-domain:8443
后续
本文搭建的节点池,实用性很低。因为很多爬虫任务并非每次请求都需要换 IP,而是要在IP 被封禁后才进行更换,反而一直更换 IP 会导致风控(特别是需要 Cookie 的时候)。
Clash Meta 也提供了很好的 API,这就可以实现动态切换节点,一个简单的方法是在爬虫程序上做检测:如果 IP 被封禁后,调用 Clash Meta 的 API 切换节点(这部分可以参考 Yacd 等前端的代码)。
但 Clash Meta 也存在局限性:不适合多用户或者多任务。简单来说就是多个爬虫同时运行的时候(爬虫都用了 Clash Meta 的代理端口),所有请求都会通过同一个节点上,如果有一个切换,那么所有的节点都会切换。一个简单可行的 Workaround 就是一个爬虫程序对应一个 Clash Meta 实例,但会比较消耗资源。
等到有需求的时候,或许可以简单实现一下,做一个中间层。