2026-04-21 11:00:19
最近搬了新家,顺手开了一条 2000M 的宽带,家里的网络设备也正好趁这个机会重新折腾一遍。这篇就当是一次记录,也顺便给以后留个备忘。
一开始为了省事,我先买了一台 TP-LINK 的 Wi-Fi 7 路由器 BE7200,四个 2.5G 口加四个 1G 口。单看硬件规格其实挺能打,拨号、测速都没什么问题,2000M 的带宽基本也能跑满。
但系统功能就不太够了。我想要的是一个「能自己折腾」的主路由:能自动分流,能屏蔽一些广告和追踪域名,最好还能把代理直接放到网关上,LAN 里的设备不用单独配置就能自动分流。TP-LINK 的固件明显还是面向普通用户的,这些需求基本没法满足。
正好手头还有一台几年前买的 N100 小主机,四口 2.5G,拿来跑软路由绰绰有余。最后定下来的架构是这样:
这样拆开之后,职责会比较清楚:iKuai 只负责「稳定的基础网络」,Debian 负责「很可能被我反复改配置」的代理部分。就算哪天代理被我搞挂了,把 Debian 关掉,家里的基础网络也还能照常用。
N100 的四个 2.5G 网口分别是 ETH0 到 ETH3。分配方案是:
这么做马上会遇到一个问题:iKuai 独占这三个口之后,PVE 的管理口 ETH0 和 iKuai 的 LAN 在物理上就是隔开的。即使两边都配在 10.10.10.0/24 这个网段里,也还是互相访问不了。总不能再浪费一个口,专门把 ETH0 接回 LAN 吧。
解决办法其实也简单:在 PVE 里给 iKuai 虚拟机额外挂一张 虚拟网卡(virtio net),然后在 iKuai 里把这张虚拟网卡和 LAN 口桥接起来。这样相当于在 iKuai 内部搭了一座桥,PVE 的管理网络就能通过这张虚拟网卡接到 LAN 里。ETH0 这个物理口反而可以完全空着,数据只走虚拟网卡。
配完之后,所有端口协商都在 2.5G,基础网络这一层就算理顺了。
旁路由这边,我花的时间就多一些。
最想用的其实是 Surge VM Gateway。规则语法熟,日常 Mac 上也一直在用。但现在手头已经没有闲置的 Mac mini 可以拿来当网关了(一台在日本,另一台在另一个家里),所以只能看 Linux 方案。
第二选择是 dae。dae 的设计很简洁,基于 eBPF,功能不多但刚好够用,本来挺合我胃口。结果试了一下发现它不支持 Shadowsocks 2022,而我用的大部分都是 ss2022 和 snell,没办法,只能放弃。
最后还是落到了 sing-box 上。sing-box 的协议支持很全,但配置复杂度也确实有名,官方文档又分散在一堆子页面里,手写 JSON 会很费劲。我比较懒,直接把 ssh 交给 Claude Code(Opus 4.7),再把我 Surge 的 conf 文件丢过去,让它参考里面的分流规则,直接生成并部署 sing-box 配置。效率确实高了很多。
配完之后,v4 用起来没问题,但 v6 开始有点意思了。
先说下背景。我的代理节点是有 global v6 的,宿主机走代理 curl -6 ip.sb 也能正常返回 node 的 v6 地址。但是 LAN 里的客户端(手机、Mac)拿到的 v6 只有 link-local fe80::,基本等于没有可用的 v6 地址,自然也发不出 v6 流量。
原因是 iKuai 这边没有 v6 上行,也没有从上游拿到任何可以下发给 LAN 的 v6 前缀。那这种情况下,要怎么让客户端「用上 v6」?
答案是:自己在 LAN 里造一个 v6 前缀。具体做法是在 Debian 上用 radvd 广播一个 ULA(Unique Local Address) 前缀 fd00:dae::/64,让 LAN 客户端通过 SLAAC 自动配出一个 ULA 地址。
这里的关键是:ULA 在 v6 里有点像 v4 的 10.0.0.0/8 这种私有地址段,不能直接出公网。但我并不需要 ULA 真的能跨运营商路由出去。客户端发出的 v6 流量会被 sing-box 的 TUN 截获,最后通过 proxy node 的 global v6 出境。外面看到的源地址是 node 的 IP,不会看到 LAN 里的 ULA。对我这套环境来说,ULA 更像是一张 v6 世界里的「临时发车牌照」:先让客户端愿意生成 v6 流量,后面再交给 sing-box 送到真正有 v6 的出口。
除此之外 Debian 侧还要做几件事才能让这套跑起来:
net.ipv4.ip_forward=1、net.ipv6.conf.all.forwarding=1、net.ipv6.conf.ens18.forwarding=1(radvd 启动时会专门检查接口级别的 forwarding);send_redirects=0:不然 kernel 会发 ICMP Redirect,告诉客户端「直接找 10.10.10.1 更快」,客户端就会绕过旁路由;iptables FORWARD 放行 tun0 的入和出:Docker 会把 FORWARD 默认策略改成 DROP,导致 UDP / ICMP 在 ens18 → tun0 这条路径上被丢掉,TCP 反倒没事(因为走的是 REDIRECT 转本地,不走 FORWARD);fd00:dae::1/64 的静态地址:sing-box 的 auto_redirect 是从接口上读 v6 前缀加进 nftables 的 inet6_local_address_set 的,没有这个地址,LAN 前缀就不会进 set,v6 转发规则全部失效(参见 sing-box issue #3698)。v6 通了之后,又遇到一个挺微妙的问题:打开国内一些 App(微信、抖音、小红书之类)的时候,经常要点好几次内容才加载出来。网页和国际 App 倒是完全没问题。
排查了一圈,原因是这样的:
TUN + radvd 让 LAN 客户端拿到了 v6 地址,所以客户端发起新连接时会做 Happy Eyeballs:同时试 v4 和 v6 两条路径,哪条先连上就用哪条。
国内大厂的 API 域名现在基本都有 AAAA 记录(腾讯、阿里、字节都在上 v6),但它们的 v6 CDN 通常只在国内 ISP 的 v6 链路上好用,也就是得从运营商的 v6 线路直连过去。
而我这边的出口情况是:
按照我的分流规则,国内 App 的 API 命中 geosite-cn → 走 direct → 客户端先试 v6 → 超时(默认 250ms 到 2s)→ Happy Eyeballs 回退 v4 → 成功。于是第一次连接会卡一下,再加上 App 自己的重试 / 缓存逻辑把这个体感放大了,看起来就像是「点一下没反应,再点一下才行」。
国际站不受影响,是因为它们命中 proxy 规则,代理节点有真 v6,直接就通了。
解决也很小,只要给 sing-box 的 direct outbound 加一个 ipv4_only:
配完之后,国内 App 的点按体感马上就正常了。
整套架构跑下来,主路由 iKuai 管稳定,旁路由 Debian 管分流,管理面板用 metacubexd,v4/v6 都能用,家里每台设备不用单独配置就能自动走分流。相比之前一台 BE7200 裸拨号的方案,可玩性和可控性确实高了不少。
唯一比较「耗心力」的是 v6 这一块,踩了好几个坑才理清:「LAN 要有 v6 地址,客户端才会发 v6」「ULA 不是为了出公网,而是为了让客户端愿意生成 v6 流量」「direct 出口没 v6,但客户端有 v6,就会触发 Happy Eyeballs 回退」。这些点想明白之后,以后再配类似环境应该会轻松很多。
接下来还有几件事想慢慢补上:先把分流规则再细一点,尤其是国内 App、AI 服务、流媒体这些容易走错出口的场景;再加上 DDNS,方便在外面稳定访问家里的入口;最后把 Tailscale 也配起来,之后人在外面排查网络或者访问家里服务会省事很多。
AP 也想换掉。现在 BE7200 在这套架构里只是当 AP 用,感觉有点大材小用。也许换成小一点的 Wi-Fi 7 AP 就够用了。
2026-04-05 11:37:18
这一次我从新潟搭「海里」去酒田,抵达酒田之后,再搭特急列车回新潟,最终赶回東京。结果特急列车和回東京的新幹線换乘时间比较短,当时也急着回東京,备用机就忘在了前排座椅靠背后的置物袋里。等新幹線已经从新潟出发了,我都还没意识到,直到突然弹出一条 Find My 通知,我才想起来手机没拿。于是马上就在下一站長岡下车,再搭新幹線回新潟。因为这次旅行买的是五天的 JR EAST PASS,所以这样来来回回折返,全程都没有任何额外费用,全部包含在 PASS 里。和朋友商量后,我们决定先在長岡站的 Lost and Found Office 登记一下,好让新潟那边的工作人员留意。全程工作人员态度都特别好,也帮忙打电话联系,说手机应该没有丢,只是那趟车现在已经回车库了,所以今天可能拿不到。对方让我们先回東京,等后天再过来取,或者直接帮我寄到新宿。因为我是后天傍晚的航班离开日本,宅急便意味着我离开之前拿不到手机。后来我们还是决定坐新幹線回新潟,在路上的时候,大概还不到一个小时,長岡站的工作人员就打电话联系我们了,说手机已经找到了,让我后天下午两点准时去取就行。到了新潟站之后,我们又去了 Lost and Found Office。工作人员立刻意识到这就是刚刚打电话说过的那部手机,对应的登记单也已经提前打印好了。那张纸上有各种情况说明,以及车库那边拍摄的我手机正反面的照片。那时候我就很放心了。朋友帮我和他们沟通了一下,结论还是今天拿不到。我们说自己打车去车库,他们说没有人可以进车库,他们的工作人员也进不去,只能等后天车库那边把手机通过宅急便送到车站。他还说快递员一般 12 点左右就会开始送货,所以下午 2 点我再去取就可以了。即使车库离车站只有 2 英里左右,我也尊重他们的规定,毕竟是他们在免费帮我找回我自己粗心落下的物品。
今天早上我又搭新幹線从東京来新潟。一路上我时不时就在看 Find My,一直关注手机到哪里了。我发现今天早上的时候,定位就已经出现在邮局了,基本上就说明今天稳稳会送到。在我还在路上的时候,我又看到快递员已经到车站附近了。等我 11:29 AM 到达新潟的时候,手机定位已经在车站了。我走到 Lost and Found Office 的时候,设备甚至已经显示 With You 了。还好我的手机没有开蜂窝,耗电很少,所以这几天都还能通过附近的 iPhone 获取定位,类似 AirTag,这也许就是 Apple 很强大的功能之一。
在 Lost and Found Office 排了一会队之后,我签了一份领取文件,工作人员从密封袋里拿出手机,让我检查是否完好,然后让我当场解锁手机、出示证件,流程就完成了。总体体验还是相当丝滑。我人生中第一次把手机落下,没想到是在日本,但也很幸运是在日本。就像朋友跟我说的,你不用担心,一定不会丢。
2026-03-13 18:44:53
本文仅代表个人观点浅谈 OpenClaw
我并不是在否定 OpenClaw 的价值。相反,我觉得它很有意思,也确实能解决一部分真实需求。但如果问题是“它更适合谁”,我的答案很明确:它更适合小白用户,而不是开发者。
很多人讨论 Agent 产品时,习惯把“能不能做事”和“适不适合我”混在一起。OpenClaw 当然能做事,这点没有问题。问题在于,它完成任务的方式,决定了它更像是一个降低门槛的消费级入口,而不是一个让开发者长期依赖的高效工作流系统。
对小白用户来说,OpenClaw 的价值非常直接。用户不用写代码,不用自己搭工具,只需要把任务说出来,系统就会尽量去完成。哪怕过程不够优雅,哪怕中间有些试探和冗余,只要最后能把事情做完,它就已经创造了价值。
但开发者看问题通常完全不一样。开发者会本能地问几个更现实的问题:这个流程稳定吗?能重复吗?值得长期跑吗?是不是每次都要重新消耗大量 Token 才能完成?如果一个系统的能力很难沉淀、很难复用、很难控制成本,那么它对开发者的吸引力就会迅速下降。
我觉得很多人会高估 OpenClaw 自身的“智力”。它当然有自己的工程价值,比如调度、交互、工具编排、上下文组织,但真正决定上限的,通常还是底层模型本身。
换句话说,OpenClaw 聪不聪明,很多时候并不是 OpenClaw 决定的,而是你给它接了什么模型决定的。模型越强,它看起来越聪明;模型越弱,它的表现就越容易不稳定。
而这会直接引出一个现实问题:好的模型往往特别贵。
至少在 2026 年第一季度 这个阶段,我并不认为我们已经进入了一个可以完全忽略 Token 成本的时代。高质量模型依然很贵,长上下文依然很贵,频繁调用依然很贵。OpenClaw 这类产品又不是一次调用就结束,它往往要持续观察、持续判断、持续规划、持续执行。每多一步,都意味着更多 Token 消耗;如果还夹杂网页浏览、截图理解、页面状态判断和失败重试,成本会被进一步放大。
更关键的是,大量消耗 Token 也不一定能解决问题。模型更贵,不代表任务就一定更稳定;上下文更长,也不代表它一定更理解网页现在到底发生了什么。很多时候它只是花了更多钱,在一个缺少结构化接口的环境里反复试错。
这也是为什么我一直觉得,至少在当前阶段,开发者不可能完全不考虑 Agent 的成本结构。未来当然可能不一样,也许 Token 会便宜到几乎可以忽略不计。但至少今天,尤其是在 2026 Q1,这还不是现实。
我现在很明确的一点是,OpenClaw 不应该被当成“什么问题都值得调用一次”的万能入口。
如果你只是想问一句:“现在 New York 的天气怎么样?”那在我看来,这类任务交给 OpenClaw 几乎没有意义。更直接的方法显然是打开 Google 搜索,或者直接看天气 App。这个问题既不复杂,也不需要多步骤执行,更不需要 Agent 去规划、调用工具、理解上下文。
所以我认为,OpenClaw 的初衷本来就不应该是替代搜索框。它真正应该发挥价值的地方,是那些需要多个步骤、多个工具、多个状态切换的复杂任务。比如跨几个系统整理信息,根据中间结果继续决策,在一组受限工具之间完成完整流程。这类任务才是 Agent 的主场。
如果只是把它用来回答一些原本一秒钟就能搜索得到答案的问题,那不仅没有发挥出 Agent 的优势,反而会放大它在成本、延迟和执行冗余上的问题。
OpenClaw 里我最认同的一部分,其实就是 Skills。
没有 Skills 的 Agent,很多时候只是一个会读页面、会操作浏览器、会尝试点击按钮的模型外壳。它也许能完成任务,但过程通常成本高、不稳定,而且对上下文极度依赖。Skills 的价值就在于,把一部分高频能力封装起来,让 Agent 不用每次都重新猜。
但问题也非常明显:Skills 再重要,也不可能完整。
真实世界的工作流是不断变化的。今天你要处理邮件,明天你要筛选简历,后天你又可能要同步 Notion、发 Slack、监控小红书、抓取某个内部后台。只要场景在变,新的能力封装就会一直出现。你不可能指望一个技能仓库在某一天突然“完整”。
而这里就出现了一个很现实的矛盾:
Skills。也就是说,小白用户是受益者,开发者却往往是那个需要不断填坑、不断补工具的人。
从这个角度说,OpenClaw 更像一个把复杂性转移给开发者、再把便利性交给普通用户的系统。它不是没有价值,但它的价值分配,本身就是偏向非开发者的。
很多 Agent 产品喜欢展示浏览器自动化,因为它很直观,也很像“人类在操作电脑”。模型打开网页、截图、识别界面、判断应该点击哪里,然后一步步往下走。这个演示通常很好看。
问题是,好看不等于高效。
比如你让 OpenClaw 去监控小红书的帖子,如果平台没有公开 API,那么它大概率只能通过访问网页、不断截图、判断页面状态、决定下一步点哪里,最后再把结果返回给你。
这种方式的问题并不是“做不到”,而是它在工程上很不经济:
开发者对这种模式通常会天然不耐烦。因为这本质上是在用模型推理去弥补工程接口的缺失。如果一个任务需要靠模型反复截图、反复理解、反复尝试,才能勉强做完,那它多半不是一个好的长期解法。
一次性的任务也许还能接受,但如果这是一个长期、重复、每天都要跑的任务,开发者首先想到的通常不会是“让 Agent 每天重新看图和思考”,而是“我要不要直接为这个场景做一个专门的工具”。
我自己做 MailClaw,其实就是在解决同一类问题:如果一个 Agent 需要处理邮件,最优解到底是什么?
如果走浏览器路线,Agent 当然可以登录网页邮箱,搜索邮件、阅读邮件、筛选发件人、导出内容,甚至模拟点击删除。但这个方案太重了,也太浪费。
所以在 MailClaw 里,我选择的是另一条路:
mailclaw CLI,支持 macOS、Linux、Windows。这样一来,Agent 如果要“读邮件”,就不需要打开浏览器,不需要截图,不需要观察网页结构,也不需要一边看页面一边决定下一步该怎么点。它只需要执行类似下面的命令:
mailclaw list --q partnership --json
mailclaw get clx123abc --json
或者直接调用 API:
GET /api/emails
GET /api/emails/export
GET /api/emails/:id
从 Agent 的角度看,这种设计的优势非常明显:输入更结构化,输出更结构化,速度更快,成本更低,可重复性更强,权限控制也更清晰。
这也是为什么我后来在 MailClaw 的 Skill 设计里,刻意让 Skill 去调用本地 CLI,而不是让它直接拿浏览器或者 curl 到处拼请求。因为在我看来,Skill 最好的角色不是替代工具,而是成为工具的入口。
前者意味着你把复杂能力堆进 Skill 里,让模型现场发挥;后者意味着你先把真正稳定的能力做成 API、CLI 或服务,再让 Skill 去发现、调用和编排。对开发者来说,显然后者更可靠,也更经济。
这也是我对 OpenClaw 最核心的看法:它的问题不在于 Agent 不够聪明,而在于很多场景下,它缺少一个足够强、足够低成本、足够结构化的工具层。
如果工具层不存在,OpenClaw 就只能退回到“看页面、猜页面、操作页面”的通用模式。这个模式当然灵活,但它也意味着高 Token 消耗、高不确定性,以及很差的工程沉淀效率。你当然可以不断换更强的模型、接受更高的账单,但结果未必线性变好。因为真正的问题未必是“模型不够聪明”,而可能是“任务根本没有被工具化”。
开发者通常会更愿意做这些事情:
从这个意义上说,OpenClaw 对开发者当然不是完全没用。它仍然可以是一个不错的交互层、调度层,甚至是原型验证工具。你可以先让 Agent 帮你跑通一个流程,再观察哪些地方值得被固化成真正的程序。
但如果一个开发者长期依赖 OpenClaw 去做所有事情,而不是把高频能力沉淀成工具,那么最后很可能得到的是一个“看起来什么都能做,实际上哪里都不够经济”的系统。
所以我的观点还是那句:OpenClaw 更适合小白用户,而不是开发者。
对小白用户来说,它最大的价值是降低门槛。哪怕背后过程不够优雅,只要能把事情做完,就是价值。
但对开发者来说,OpenClaw 更适合扮演“外层入口”,而不是“最终执行层”。开发者真正应该投入精力的,不是让 Agent 在浏览器里多走几步,而是尽快把高频场景抽象成稳定的 API、CLI 或服务。
Skills 很重要,但它不应该是能力本身。它更像是能力的索引、说明书和调度接口。真正决定效率上限的,仍然是你背后有没有一个足够好的工具系统。
未来也许会不一样。也许有一天,Token 会便宜到几乎可以忽略不计,浏览器式 Agent 的高消耗不再值得在意。到了那个时候,也许今天很多批评都会失效。
但至少在 2026 年第一季度,我不认为现实已经走到那一步。今天的开发者仍然需要在效果、稳定性、速度和成本之间做平衡。而在这个平衡里,盲目消耗更多 Token,通常不是最优解。
对于开发者来说,这部分 Token 预算,很多时候已经足够拿来创造一个全新的工具了。
2026-03-02 04:22:30
I finally replaced my old comment setup and moved everything to a new system built by myself.
The result is simple: my blog is now fully running on Cloudflare.
This post explains why I migrated from Artalk, what I built, and how the migration worked.
Artalk is a great project, and it worked well for me for a long time. I used it as a reference while redesigning my own system.
But I wanted tighter control over:
So instead of extending Artalk, I built a focused API-first comment service for my own use case.
The current architecture is intentionally minimal.
The frontend is custom, integrated into my Hugo theme, and styled to keep the previous reading experience close to what I had before.
No separate admin panel or heavy UI dependency in the backend. The Worker exposes clean endpoints for posting comments, listing comments, and stats.
Each comment keeps parent_id, root_id, and depth, and public listing supports page-based pagination.
AUTO_APPROVE controls default behavior:
AUTO_APPROVE=false: new comments are pendingAUTO_APPROVE=true: new comments are approved immediatelyIn both modes, Telegram notifications are sent.
Approve / Spam / Delete
Spam / Delete
Reserved admin emails are blocked from public submission, so regular users cannot pretend to be the site owner.
Avatar URLs are generated from email via Gravatar hash.
For network metadata, the system uses api.ipinfo.es and stores country, ASN, and related fields in D1. Country display uses full country name and a separate country code for flags.
API timestamps are normalized to include timezone offsets, so old imported comments and new comments use a consistent format.
I migrated historical comments from an Artalk export file (.artrans) into D1.
High-level process:
.artrans to D1-compatible SQL with a converter script.This gave me a smooth transition without losing old threads.
I wanted one platform for everything.
Now the entire blog stack is inside Cloudflare:
No extra VM, no extra database vendor, no mixed ops stack.
This system is built for my blog first, but the architecture is reusable.
The most important part for me is that I now control the full comment pipeline end to end: data model, moderation workflow, frontend behavior, and deployment.
Migrating from Artalk was straightforward once the converter and D1 migrations were in place.
2026-02-14 14:46:19
现在正在 湘南新宿ライン 的 Green Car,前段时间从「上野(御徒町)」去「房総半島」玩,奇怪的发现我来回支付的价格不一样,而且最关键的是完全违背常理。
其中在「錦糸町」出站,支付了 ¥167,之后从「錦糸町」入站直接到「富浦」出站,支付了 ¥1980,合计 ¥2147。
直接从「富浦」入站,到「御徒町」出站,支付了 ¥2310。
细心的朋友已经发现问题了。我连续计费从头坐到尾的价格竟然比出站之后重新入站更贵。也就是说你坐的路程越长,单价并不一定更低,这完全违背了基本常识。
这是一个非常经典的 JR 运费计算"Bug"(其实是由于运费区间的阶梯定价机制造成的)。
简单来说,你"出站再进站"的操作,正好让你避开了一个昂贵的运费跳档。
这里是具体的数学拆解:
1. 核心原因:运费的"阶梯"跳得太高了
JR 东日本的运费是按里程分段计价的。随着距离增加,每一段的价格会跳涨。你正好处于一个临界点上:
锦糸町 > 富浦 的距离大约是 118 km
御徒町 > 锦糸町 的距离大约是 4.4 km
2. 连续计费的陷阱
当你不出站,直接从 富浦 > 御徒町 时,里程是累加的:
3. 算一笔账
| 方式 | 价格计算 | 总价 |
|---|---|---|
| 分段买 | 1,980 (长途) + 167 (短途) | 2,147 日元 |
| 连续买 | 升级到下一档运费 | 2,310 日元 |
差价原因:
JR 的运费表里,从"101-120km"升级到"121-140km"这一档,价格一口气涨了 330 日元 (2,310 - 1,980)。
而你实际多坐的那段路(锦糸町-御徒町)单独买只需要 167 日元。
因为 330 > 167,所以被系统"自动升级"到下一档反而更贵,手动拆开反而便宜。这在 JR 的运费体系中属于一种已知现象,通常发生在长途旅行刚好卡在某个运费区间边缘,再多坐几公里就会触发"大额跳档"的时候。
2026-01-05 21:48:57
日本的 SAKURA Internet Inc. (AS9370) 即使在近些年大不如前,但仍然因为其 IP 质量(接近日本家庭宽带),再加上无限流量,备受玩家喜爱。当然这家的机子也并不好买,需要日本的真实地址,以及日本的手机号。
主播在大概半年之前注册了一个 SAKURA 和 WebARENA Indigo 帐号,一直在使用 SAKURA VPS,一直存在的问题就是从中国到日本根本跑不满限速的 100Mbps。因为存在国际 QoS 的问题。
这个方案也一样适用于 Indigo。简单来说,就是用一台主流的商宽 VPS (比如 GreenCloudVPS) 和 SAKURA 建立 GRE 隧道,然后将国际入站的流量先到 GreenCloudVPS,再从 GreenCloudVPS 的 GRE Tunnel 到 SAKURA,这样就能绕过 SAKURA 的国际 QoS 了。
玩 GRE Tunnel 的前提是你的云服务商没有禁用 Protocol 47。
在两个服务器上加载 GRE module:
sudo modprobe ip_gre
echo "ip_gre" | sudo tee -a /etc/modules
例如服务器 A 公网 IP:23.191.8.1,服务器 B 公网 IP:23.191.8.2。内网地址:10.0.0.1 和 10.0.0.2。
接下来在服务器 A 上添加一个 GRE 接口:
nano /etc/network/interfaces
auto tun-gre
iface tun-gre inet static
address 10.0.0.1
netmask 255.255.255.252
pre-up ip tunnel add tun-gre mode gre remote 23.191.8.2 local 23.191.8.1 ttl 255
post-up ip link set dev tun-gre mtu 1450
post-down ip tunnel del tun-gre
在服务器 B 上同样添加 GRE 接口:
nano /etc/network/interfaces
auto tun-gre
iface tun-gre inet static
address 10.0.0.2
netmask 255.255.255.252
pre-up ip tunnel add tun-gre mode gre remote 23.191.8.1 local 23.191.8.2 ttl 255
post-up ip link set dev tun-gre mtu 1450
post-down ip tunnel del tun-gre
测试 GRE Tunnel 是否成功:
在服务器 A 上:
ping 10.0.0.2
像我这样就是成功了,而且两个服务器之间有着非常优秀的网络质量。
ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=1.79 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=1.80 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=1.89 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=1.83 ms
64 bytes from 10.0.0.2: icmp_seq=5 ttl=64 time=1.77 ms
64 bytes from 10.0.0.2: icmp_seq=6 ttl=64 time=1.88 ms
64 bytes from 10.0.0.2: icmp_seq=7 ttl=64 time=1.68 ms
64 bytes from 10.0.0.2: icmp_seq=8 ttl=64 time=1.87 ms
64 bytes from 10.0.0.2: icmp_seq=9 ttl=64 time=1.81 ms
64 bytes from 10.0.0.2: icmp_seq=10 ttl=64 time=1.92 ms
64 bytes from 10.0.0.2: icmp_seq=11 ttl=64 time=1.71 ms
64 bytes from 10.0.0.2: icmp_seq=12 ttl=64 time=1.77 ms
64 bytes from 10.0.0.2: icmp_seq=13 ttl=64 time=1.99 ms
64 bytes from 10.0.0.2: icmp_seq=14 ttl=64 time=1.71 ms
^C
--- 10.0.0.2 ping statistics ---
14 packets transmitted, 14 received, 0% packet loss, time 13021ms
rtt min/avg/max/mdev = 1.680/1.814/1.987/0.083 ms
最后只要配置 nftables 将流量从服务器 A 的 GRE Tunnel 转发到服务器 B 的 GRE Tunnel 即可。
nano /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table ip my_proxy_forward {
# 处理入站 DNAT
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
# 将发往 A:32767 的流量转发到 B 的隧道地址 10.0.0.2
tcp dport 32767 dnat to 10.0.0.2
udp dport 32767 dnat to 10.0.0.2
# 将发往 A:26002 的流量转发到 B 的隧道地址 10.0.0.2
tcp dport 26002 dnat to 10.0.0.2
udp dport 26002 dnat to 10.0.0.2
}
# 处理出站 SNAT (Masquerade)
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# 确保回程流量通过隧道:
# 当流量发往 B 的隧道 IP 时,将源地址改为 A 的隧道 IP (10.0.0.1)
ip daddr 10.0.0.2 oifname "tun-gre" masquerade
}
}
最后启动 nftables 即可
sudo nft -f /etc/nftables.conf