异地组网
构建之初是希望我的网络在使用上能够像一个局域网一样,其实就是 VPN。
按节点之间的通信来分,VPN 可以分为传统的 C/S 架构以及最近流行的 P2P 架构。
C/S 架构需要一个中心服务器来传输流量,代表软件如 OpenVPN。由于所有服务器都需要经过中心服务器,中心服务器自然成为了网络的瓶颈之一。如果是有大带宽的需求,在中国目前商宽价格贵的离谱的,C/S 架构的 VPN 并不是一个好的选择(有公网 IP 的家宽也可以考虑)。
P2P 架构的 VPN 也成为 Mesh VPN,网络内节点之前连接是直连的,而不用通过某个特定的服务器。这类产品一般会有一个协调服务器记录一下各个节点的信息,当 A 节点想要连接 B 节点的时候,只需要从协调服务器获取对方的 IP 和端口,再发起连接即可。传输过程不需要任何中心服务器的参与,是点对点传输的。
然而实际的网络环境会复杂的很多,稍微加个防火墙规则就可以阻断这种 IP + 端口的传输。所以很多 Mesh VPN 的产品会有一个 Relay 的设计,通过网上一个公开的节点中转数据,以此绕过防火墙规则。
下面我就一些正在使用的产品进行介绍。
Tailscale
Tailscale 是基于 Wireguard 的 P2P VPN,即传输层用的是 Wireguard。考虑到网络环境的复杂性(例如 ISP 会禁用 Wireguard 或者封锁 UDP,全锥形 NAT 等),Tailscale 还设计了 Derp,这样数据包在 HTTPS 的基础上进行中转。
中国移动畅连
中国移动畅连是中国移动推出的异地组网软件。从抓包的数据来看,也是基于 UDP 通信的。
优点:
- 中国移动官方的中转服务器,带宽大,我从广西到北京能跑到 30M,抓包看服务器似乎在江苏那块
- 价格比较便宜(5元/月)
缺点:
- 免费版限制非常多,只能5个设备
- 中转服务器的位置对于某些场景(如北京到北京,要去到江苏再回来)可能会增加延时
- 占用内存大,用的是 Electron
- 缺少 Linux 的支持
- 缺乏 DNS 的支持
- 不能转发子网段
目前发现有一个产品上的漏洞,免费版本的用户在界面上使用远程/RDP/SMB 都会提示免费版不可用,但直接用组网的 IP 是可以访问的,所以可以通过 RDP 或者 NoMachine/Moonlight 等直接通过 IP 访问。
题外话
构建 VPN 是为了节点之间能够互相访问,大部分情况下,意为着你信任这些节点。
当你连接一个不受信任的节点,大部分情况下,用户需求是:
- 我可以访问这个节点的所有资源
- 这个节点不能访问我的网络
这时候使用 VPN,那就有些不够安全了,当然可以通过配置 ACL 来限制节点之间的访问或者使用防火墙,但属实有些麻烦。
比较好的办法是使用 HTTP/Socks 代理,如果网络环境不好,可以套上一层加密/混淆,比如 SS、SSR、V2ray 等。
Hostname、域名以及 DNS
当网络节点数量增多,IP 数量也随之增加,这时候记 IP 是不可能记了,需要换成 Hostname 或域名等有语义化的方式,这也是 DNS 诞生的背景。
使用搜索域减少输入
而相比域名,我更喜欢使用 Hostname 来访问,需要输入的字符更少,至少不用把手移过去输入 .
。
然而对每台机器设置 Hostname 比较麻烦,而且 Tailscale 默认只认 Tailnet 上的 Hostname,子网段的机器是不认的。
我用了 DNS 服务器 + DNS 搜索域来解决上述问题。DNS 服务器我用的是 Technitium DNS,运行在国内的 VPS 上。
DNS 服务器维护一个 Zone,以 bb
后缀为例,比如 abc.bb
指向 127.0.0.1
。
然后在 Tailscale 管理界面上设置 DNS 服务器以及对客户端下发搜索域(Search Domains)。
Hostname 命名规则
遵循一个命名规则,可以快速记住 Hostname,或者在回想 Hostname 的时候作为线索。
规则根据自己的需求、偏好来指定就好,比如我的朋友是根据设备型号来作 Hostname。
这里分享一下我的命名规则:
对于位置、网络接入固定的机器,其 Hostname 组成是 {类型}-{位置代码}{序号}
- 类型是机器的网络环境
vps
:有固定的公网 IPv4node
:无固定的公网 IPv4vmh
:意为 virtual machine host,托管 VM 的宿主,在网络中都是运行 PVE 机器
- 位置代码,指的是网络接入所在城市的机场的 IATA 代码或车站拼音码
- 比如在北京的机器,那么就取北京首都国际机场的代码,PEK
- 如果所在城市有多个机场,取最早建设的机场代码,比如北京用的是 PEK(首都国际机场),而不是 PEX(大兴机场)
- 如果所在城市没有机场或没有机场没有 IATA 代码,则使用
S{拼音}
,拼音就是省名+城市名的拼音首字母,比如河南新乡就是 HNXX。
- 序号:从0开始,只有类型和代码相同的时候,才递增
对于不固定的机器,如手机、笔记本电脑等,其 Hostname 就是一个设备型号或其他助记符
根据以上规则,举几个例子:
- 阿里云北京服务器:
vps-pek0
- 北京移动公网 IP 节点(非固定):
node-pek0
- 北京移动无公网 IP 节点(非固定):
node-pek1
- 一加5手机:
op5
- Macbook Air M1:
m1
关于给 Hostname 取名字,IETF 还出了一个 RFC 作为建议:https://datatracker.ietf.org/doc/html/rfc1178
代理/隧道/端口转发
Mihomo(Clash Meta)
Clash 的分支版本。亮点是内置了订阅处理、支持更全面的协议(如 hysteria 系列、Wireguard)。
目前使用场景:
- 优化国内外节点通信:一台上海电信的节点和香港 VPS 建立通信,由于 VPS 线路比较差,直连会绕地球半圈。用 Clash Meta 接入一些机场的节点作为中转可以很好改善这类情况。由于确定了线路,只需要在
proxy-providers
中添加订阅地址,再使用filter
字段筛选出香港的节点。 - 在客户端上分流:内网上有两个教育网的节点,在线情况不稳定,偶尔用于通过教育网出口去查询一些资料。在节点开启 Socks5 代理监听后,再添加到 Clash 的配置中,并设置负载均衡的策略。
Gost
Gost 一般用来快速搭建端口转发,当然作为隧道、代理也是可以的。Gost 的优点就是简单,无需配置文件,直接命令行启动,非常适合快速或临时操作。在 Linux 上希望作为后台运行,也只需要编写一个 type=simple
的 Systemd Service 即可。
内网穿透:Cloudflare Tunnel + 前置代理
由于我海外的 VPS 中,配置/线路至少烂一个。所以我的服务一般不会部署在海外的 VPS 上。国内 VPS 在配置会好一些,但带宽太小,更主要是域名需要备案,比较麻烦。所以选择走“内网穿透”这条线路。
内网穿透比较热门的是 Frp,但前面也说了线路垃圾或者带宽以及备案的原因,使用 Frp 这类走公网服务器中转的线路是不太好使的。国内的商业产品(如花生壳)性价比不高。
相比之下,Cloudflare Tunnel 不仅免费,而且体验也是比较好的,说说其优点:
- 自动的 HTTPS:反代本地的 HTTP 服务,不需要手动设置证书
- 速度快:得益于 Cloudflare 数量庞大的节点
- 除内网穿透,也支持组网以及非 HTTP(S) 的端口转发,但需要相关设备安装其客户端
当然缺点也是有的:
- 对于内网穿透,Cloudflare 实际上只允许 Web 内容暴露到公网,甚至连 Websocket 都不行(我测试下来没法连接)。
- 不允许大流量,Reddit 上有用户反馈说超过 1TB 后,官方会联系上本人
- 隐私/安全,毕竟把流量托管给 Cloudflare 了
如果需要暴露到公网的服务都是 HTTP,选择 Cloudflare Tunnel 还是很不错的。
前置代理呢?如果直接把部署在国内的服务通过 Cloudflare Tunnel 暴露出去,一到网络高峰时间段,国内节点到 Cloudflare 节点的线路会爆炸,表现为几乎不可用。前置代理就是用来改善两者之间的线路。
但 Cloudflare Tunnel 并不支持直接设置代理,官方也说明了不会支持,软件也不会认如 HTTP_PROXY
等环境变量。
所以需要在本地部署一个代理,然后让 Cloudflare Tunnel 通过这个代理访问。这个代理可以是 Gost,也可以是 Clash Meta。我这里选择 Clash Meta,启动 TPROXY,通过 iptables 来实现代理。
具体看 @Xiaomage 发表的文章:https://blog.xmgspace.me/archives/cloudflare-tunnel-via-proxy.html
目前我的姿势:
- 确定连接 Cloudflared 的香港节点
- 把机场的订阅放到 Clash Meta,筛选出香港节点,并设置规则组为
url-test
,自动选择延时最低的节点,注意服务器节点不要开启流量探测。 - 开启 TPROXY,然后设置 IPTABLES 规则