最近在折腾日本落地节点,用的是 WebArena Indigo(下文简称 Indigo)。这家日本 VPS 便宜、走 NTT 线路,拿来做落地很合适。但我在「中转机 + Indigo 落地」这套架构上踩了个不小的坑,折腾了大半天才定位清楚,这篇就记录一下整个过程和最后的解法。
架构与需求
需求很简单:用 Indigo 当日本落地,但 Indigo 的直连 IP 从国内访问的路由一般,所以前面再挂一台中转机(线路对国内友好),客户端连中转机、中转机把流量送到 Indigo 落地。
客户端 → 中转机 → (隧道) → Indigo 落地(snell)落地这台 Indigo 上跑的是 snell,中转机负责把入口端口的流量转发过去。问题就出在「中转机 → Indigo」这一段该怎么走。
为什么没直接用 realm 公网转发
最省事的做法当然是 realm(或 gost 之类)做个普通的公网 TCP 转发,中转机监听一个端口,直接转到 Indigo 的公网 IP。
但在 Indigo 上,走公网转发是百分之百会被限速的——把流量从中转机公网直接灌到落地的公网 IP,必然撞限速。所以 realm 这条路直接 pass,我给两台机器之间建了一条 GRE 隧道,想着把流量「包」进点对点的隧道里、看起来像内网互联,应该能躲过针对公网中转的限速。
剧透一下:隧道这个方向是对的,但只对了一半——IPv4 GRE 照样会被限速,一上量就崩;最后只有 IPv6 的 GRE 才真正躲过去。
IPv4 GRE 的坑:一跑测速就崩
隧道建好后,节点能连、能上网,平时刷网页也没问题。但只要一测速,现象非常稳定:
- 第一波数据能冲出去(一两秒、十几 MB),
- 紧接着直接
Socket closed by remote peer,测速被打断, - 换任何别的节点都正常,唯独这条经 Indigo 落地的会崩。
把 snell 摘掉、直接在隧道内裸跑 iperf3,问题原形毕露:
| 方向 | IPv4 GRE |
|---|---|
| 落地 → 中转(即下行/测速方向) | ~198 Mbps,一路下滑,重传 2.8 万+ |
| 中转 → 落地 | ~475 Mbps,重传几千 |
下行方向 8 秒重传两万八,吞吐从 235 一路掉到 154——典型的「一上量就被狠丢包、TCP 雪崩、连接被 reset」。这就是测速「第一下能跑、马上断」的根源。
排查:把嫌疑一个个排除
为了不冤枉好人,我把可能的原因逐个排掉:
- 不是 snell:直接连中转机本机的 snell(不经隧道)完全正常,说明协议和版本没问题。
- 不是 MTU:两个方向用 DF 大包打满 1500 都能过,隧道内 1450 也能过,简单的 GRE 黑洞排除。
- 不是 DNS / 出网:在落地机本机
curl直连测速源,5MB 秒下,出口带宽、源站、解析全都好的。 - 不是 qdisc 丢的:落地机网卡用的是
cake,但它bandwidth unlimited,整个生命周期只丢了几百个包,根本没在限速。
也就是说:包不是在落地机的队列里丢的,是出了落地机之后、在到中转机的这段公网链路上丢的。 落地机本机直连测速源又是满速的(出网和源站都没问题),所以矛头指向:这条路径对 GRE(协议 47)这种隧道流量,在高速率下做了限速 / 丢包。
更有意思的是,后来我拿另一台 Indigo(同机房、邻近子网)裸测不带任何 GRE 的 IPv6 直连,重传也高达四万多。这进一步说明:底层路径本身对大流量就一般,而 IPv4 + GRE 是被额外「针对」的那一层,叠起来就直接雪崩了。
解决:改用 IPv6 GRE(ip6gre)
两台机器都有 global IPv6,而且 v6 之间互 ping 延迟低、空载零丢。运营商的 QoS / policing 规则又常常只配了 IPv4,IPv6 那条路往往更干净、没人管。于是我把隧道的外层从 IPv4 GRE 换成 IPv6 GRE(ip6gre)——内层地址(10.0.0.x)和上面的转发规则一个字都不用动,只换「管子外面」。
换完立刻见效:
| 方向 | IPv4 GRE | IPv6 ip6gre |
|---|---|---|
| 落地 → 中转(测速方向) | ~198 Mbps,持续塌 | ~470 Mbps,稳定还上扬 |
| 中转 → 落地 | ~475 Mbps | ~460 Mbps |
最关键的是:不再雪崩了。测速方向稳稳跑到带宽上限附近,Surge 那边也不再 closed by peer。残余还是有一些重传(这条路底子就一般),但 TCP 能正常「骑」过去,不影响使用。
所以这篇的核心结论就一句话:在 Indigo 上做隧道中转,只有 IPv6 的 GRE 才能保证不被限速。
配置要点
建隧道(两端对称,把 local / remote 和内层地址对调即可):
# 中转机一端
ip link add tun-gre type ip6gre \
local <中转机 IPv6> remote <Indigo IPv6> \
ttl 255 encaplimit none
ip addr add 10.0.0.2/30 dev tun-gre # 落地机用 10.0.0.1/30
ip link set tun-gre mtu 1400 up几个容易忽略的点:
- MTU 要降下来。IPv6 外层比 IPv4 多 20 字节开销(IPv6 头 40 + GRE 4 = 44),1500 的底层算下来内层最多 1456。我直接设成 1400,留足余量,反正丢包不是 MTU 问题。
encaplimit none。ip6gre默认会塞一个 IPv6 封装限制扩展头,多 8 字节还可能被某些路径丢,关掉更干净。- 记得做 MSS clamp。在隧道接口上把 SYN 的 MSS 按隧道 MTU 夹一下(nftables
tcp option maxseg size set rt mtu),不然某些方向的大包还是会顶破隧道。 - 持久化别忘。我两台一台用
systemd-networkd(.netdev里Kind=ip6gre),一台用ifupdown(/etc/network/interfaces.d/),改完都要落盘,不然重启就回去了。 - 内层还是 IPv4 的
10.0.0.x,所以日常验证隧道通不通还是ping 10.0.0.1(穿隧道、外层用 v6 封装);ping 那串 v6 地址只是测两台公网底层,跟隧道本身没关系。
选机器:500M 四核 vs 1000M 六核共享
顺带说下套餐。我手上两台 Indigo:
- A:500M 带宽 / 四核 —— 日常落地中转,完全够用,能稳定跑到带宽上限附近。
- B:六核 / 1000M「共享」带宽 —— 理论规格更高,但实测没必要。
原因有两个:一是那 1000M 是共享带宽,不保证;二是这套架构真正的瓶颈在中转那段链路和路径质量,不在落地机的标称带宽——换上 B 之后单条隧道也跑不出比 A 更高的有效吞吐。所以为了这个用途,500M 四核那档就够了,没必要上 1000M 共享,省下的钱多开一台或者升级中转机更划算。
IP 质量
顺手也跑了下这几个 IP 的质量测试,贴出来给个参考:



小结
- Indigo 做隧道中转,IPv4 GRE 会被限速到雪崩,IPv6 GRE(ip6gre)才稳——这是这次最大的收获。
- 公网转发在 Indigo 上是百分之百会被限速的,所以必须走隧道;但别以为建了隧道就万事大吉——IPv4 GRE 一样会被限,只有 IPv6 GRE 能稳。
- 隧道丢包先别急着怪 GRE「性能差」:GRE 本身是很薄的内核封装,能跑千兆。先用 iperf 在隧道内裸跑、再和普通 TCP 直连对比,很快就能区分是「协议被限」还是「路径本身烂」。
- 套餐别被规格忽悠,500M 四核足矣,1000M 共享对这个场景没意义。