代理节点池搭建

    一直以来都有做一个节点池的想法,但手上的项目没有一个能用上的,一直在 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 实例,但会比较消耗资源。

    等到有需求的时候,或许可以简单实现一下,做一个中间层。此外,如果想使用的朋友可以发送电子邮件联系我。