下面对 Tailscale 如何做 NAT 穿透(包括直连建立、保持与回退)的关键原理拆开讲。

1)总体线路:三条路,优先直连

  • 优先直连(UDP over Internet):两端先尝试点对点直连,成功后所有数据都直接走这条路(性能最好、时延最低)。(tailscale.com)
  • 协商/引导与兜底(DERP):在直连之前与失败时,先经就近 DERP 中继建立“控制/引导通道”,用它交换候选地址、发起“请你打洞”等信号;若直连始终失败,则走 DERP 作为加密转发 的备胎。(tailscale.com)
  • 更细的穿透协议(DISCO + STUN):Tailscale 基于 WireGuard 自研了“DISCO”发现/心跳层,配合 STUN 获取公网映射与 NAT 类型,驱动 UDP 打洞。(tailscale.com)

2)打洞的关键“料”:同一 UDP socket、STUN、候选地址、互打

  • 同一 UDP socket:获取公网映射必须用和后续真正传数的同一个 UDP 套接字来发 STUN/接回包,否则你测到的 公网IP:端口 跟实际传输不同,洞就白打了。这是很多实现失败的根源。(tailscale.com)
  • STUN 获取外网映射与 NAT 性质:客户端向 STUN 发请求,得到“我在外面的 IP:port 是啥”,也能侧面推断 NAT 类型(如对称型更难打)。(tailscale.com)
  • 交换候选地址:双方把自己当前可用的候选 端点(endpoints)(含 IPv4/IPv6、多个 IP:port 映射)通过控制面/DERP 互换。(tailscale.com)
  • 双向同时发起(UDP hole punching):A、B 对彼此的候选 IP:port 同步“互打”若干小包(包含 DISCO 探测),在两端 NAT 上同时打开出站映射,让对方进入我的 NAT 表,从而“外部包”也能被 NAT 放行给我。(tailscale.com)

3)DISCO 层干了什么?(比 WireGuard 更懂 NAT 的“前戏”)

  • DISCO ping / 心跳tailscale ping 默认发的是 DISCO 探测,不是 ICMP;它能告诉你“目前是经 DERP 还是直连哪个 IP:port”。(tailscale.com)
  • CallMeMaybe:当 A 已经对 B 的候选端点开火时,会经 DERP 送一个 CallMeMaybe 给 B,意思是“我在打你的这些端口了,你也回打一发,把回程洞打开”。(Go Packages)
  • (新版)CallMeMaybeVia / UDP relay endpoint:还有一种 Via 形式,提示通过中继候选来协助开路(对“UDP 被限”网络更友好)。(Go Packages)
  • 选择 & 优先级:如果已经有可靠直连,端上可以不再开启新的路径;直连优先于“经中继的路径”。(Go Packages)

4)魔法插座:magicsock 把所有这些都“接”在一起

  • magicsock 是 Tailscale 在用户态的“魔法 UDP 套接字”,同一个 socket 同时承载 WireGuard 数据、STUN、DISCO,以及穿透时需要的各种小包和心跳,从而保证“测到的映射=用来传数的映射”。(Go Packages)
  • 这也是为何 Tailscale 不直接用内核态 WireGuard:因为 NAT 穿透的许多动作必须跟数据在同一个用户态 socket里做,方便灵活控制与观测重绑定(rebinding)、心跳、计时器等。(Reddit)

5)失败与回退:DERP 作为发现通道 + 永久兜底

  • 发现阶段:最初几包通常先走最近的 DERP,用于互递 DISCO / 候选地址;一旦直连打通,就切换到直连通道。(tailscale.com)
  • 兜底阶段:若遇到 对称 NAT + 防火墙 等强限制,直连打不通,就全流量走 DERP(加密、稳定,但带宽/时延逊于直连)。(iam.bitbeats.io)
  • 现实世界并不完美:官方也承认 NAT 穿透是“长期拉锯战”,需要持续遥测与改进。(tailscale.com)

6)连通保持与漫游(rebind)处理

  • 保活心跳:穿透成功后,DISCO 会以低频心跳维持 NAT 映射;社区里称过“silent disco”等优化,尽量减少无谓心跳。(GitHub)
  • NAT 重绑定:当一端公网 IP:port 变化(例如路由器重启/蜂窝到 Wi-Fi 切换),magicsock 会通过 DISCO/STUN 迅速探测到并重建可用路径。原理还是“同一 socket 上继续打洞 + 候选更新”。(Go Packages)

7)IPv6 情况

  • 双栈最优:若两端都有可达 IPv6,通常不需要穿透就能直连(无 NAT、路径更稳定);若一端仅 IPv4-NAT,仍按上面流程打洞或回退 DERP。(tailscale.com)

8)你能在现场怎么“看懂它在做什么”

  1. 看当前连接类型与路径
1
2
3
tailscale status --peers
tailscale ping <peer-name> # 默认 DISCO,输出会标明 via DERP(...) 或 via <IP:port>
tailscale ping --until-direct <peer-name> # 持续直到打出直连

这些命令能直接看到“是否直连、走哪个 IP:port、DERP 节点名”等。(tailscale.com)

  1. 网络自检
1
tailscale netcheck

用于判断 UDP 是否可出、就近 DERP、是否存在对称 NAT 等(输出因版本而异)。文档对“连接类型”、“DERP 角色”有解释。(tailscale.com)

9)把整个流程串起来(顺序图式说明)

  1. 两端启动 → 通过控制面注册/换公钥,并各自连上就近 DERP。(tailscale.com)
  2. STUN 获取自己的公网 IP:port 与 NAT 线索;把“候选端点”发给对端(经控制面/DERP)。(tailscale.com)
  3. A/B 同时对彼此候选端点发 DISCO 探测(互打)→ NAT 表里建立出站/入站映射。必要时 A 还会经 DERP 发 CallMeMaybe 让 B 主动回打。(Go Packages)
  4. 任一条直连能收发 DISCO/数据包 → 选定最佳直连路径并切换数据面到直连。(tailscale.com)
  5. 若所有直连失败 → 全流量走 DERP,同时周期性再尝试直连以便条件改变时“脱离中继”。(iam.bitbeats.io)

进一步阅读(权威/源码级)

  • 官方长文:How NAT traversal works(强烈推荐通读,解释了为何“必须同一个 UDP socket”)。(tailscale.com)
  • DERP 服务器与角色(发现与兜底)。(tailscale.com)
  • DISCO 协议与 CallMeMaybe / CallMeMaybeVia 类型(Go 包文档)。(Go Packages)
  • magicsock 源码包(用户态“魔法 socket”,NAT 打洞的执行场)。(Go Packages)
  • Ping 类型说明(DISCO/TSMP/ICMP 的区别与用途)。(tailscale.com)

大家好,我是那个曾经天真地以为“买个摄像头=万事大吉”的倒霉蛋。

你有没有经历过这样的场景?
花几百块买了个“智能家用摄像头”,画质清晰、夜视给力、手机远程查看so easy。结果用了三个月,厂商发来一条温柔又冰冷的消息:

“亲爱的用户,您的免费云存储已到期,请支付29元/月开启录像回看功能。”

什么?!一个月29?!我这是在养摄像头还是在供儿子上私立国际学校?

更离谱的是,有些品牌还玩起了“套餐制”——7天循环录像要30,30天要60,要是想永久保存?不好意思,得加钱,还得绑定他们的会员体系……仿佛你不交钱,家里的猫偷吃零食的画面就永远消失了。

于是,我含泪删掉了那段拍到我家狗子半夜翻垃圾桶的珍贵视频,并立下誓言:

我要自己当“云服务商”!


一、市面上的摄像头,不是太贵就是太坑

现在的家用摄像头,说白了就两种:

  1. 便宜的:只能实时查看,不能回放,等于“睁眼瞎”。
  2. 贵的:必须订阅云服务才能录像,每月扣你几十块,像极了爱情里的“续费关系”。

而且你还不能断订——一旦停了,之前的录像全清空,比前任删聊天记录还彻底。

这不是科技,这是数字勒索

所以,我决定反向操作:买硬件不买服务,数据本地存,自由掌握在自己手里


二、我的省钱方案:海康+录像机+Mini主机 = 家庭版“天网系统”

经过一番研究(和踩坑),我最终选择了这套组合拳:

  • 设备清单
    • 海康威视 WiFi/有线双模摄像头 ×2(约230元/台)
    • 海康威视 WiFi录像机(NVR)×1(2路约70元左右,4路约140元左右)
    • Mini主机一台(小钢炮式Windows迷你电脑,300~600元)

总价不到1000,能用五年起步,平均每天才几毛钱,连一杯奶茶都不到!

✅ 方案优势一览:

项目 传统云摄像头 我的DIY方案
是否需要月租 是(29~60元/月) 否!一次性投入
录像是否本地存储 否(全靠云) 是!硬盘说了算
手机能否远程查看 能(通过“海康互联”APP)
数据隐私安全性 厂商掌握你的生活 自己掌握一切
视频保留时间 取决于付费等级 想存多久存多久

三、怎么搭?超简单三步走!

第一步:基础搭建 —— 海康全家桶上线

  1. 把两个海康摄像头装好(一个放客厅盯娃,一个放门口防快递刺客)。
  2. 连上WiFi录像机(支持无线连接摄像头,不用拉网线,懒人福音)。
  3. 插上电源,开机自动配对。

这时候你就可以用 “海康互联”APP 在手机上看实时画面啦!是不是很爽?

⚠️ 重点提醒:
设置时一定要记住你创建的那个 admin账号和密码!这不仅是登录APP的钥匙,更是进入摄像头后台的“万能通行证”。忘了它?恭喜你,可能要重置设备从头再来……

家里网络示意图

网络

录像机

录像机

室内摄像头

室内摄像头

mini主机

mini主机


第二步:进阶玩法 —— 把录像搬到自己的“云”里

你以为这就完了?No no no,真正的自由才刚开始!

我们目标是:不让任何厂商赚我一分钱,所有录像我说了算!

怎么做?

👉 把摄像头的数据导出来,存在自己的电脑或百度网盘!

具体操作如下:

  1. 准备一台 Mini主机(比如Intel N100的小盒子,性能够用还省电)。
  2. 让它连上家里同一个网络(可以让摄像头直接接路由器,也可以直接连录像机的WiFi热点)。录像机的WIFI热点以及密码可以在海康互联APP里看到。
  3. 登入摄像头后台,获取RTSP流地址(后面细说)。
  4. 在Mini主机上跑一个叫 ZLMediaKit 的开源工具(GitHub上有,免费!),它可以接收并录制摄像头的视频流。
  5. 录下来的文件自动同步到百度网盘、阿里云盘或者NAS,实现“私有云备份”。

这样一来,哪怕你家停电、设备损坏,视频还在云端躺着笑你:“主人,我活得比你还久。”

摄像头使用ZLMediaKit参考链接:https://ownding.com/2025/06/06/%E6%B5%B7%E5%BA%B7%E6%91%84%E5%83%8F%E6%9C%BA%E5%BD%95%E5%83%8F%E6%9C%BA%E5%AF%B9%E6%8E%A5%E6%96%B9%E5%BC%8F%E8%AE%B0%E5%BD%95/


四、如何找到摄像头IP并登入后台?

很多人卡在这一步,其实很简单,只需要一点点“黑客精神”(别怕,合法的那种)。

方法一:通过录像机找IP

  1. 用手机连上录像机发出的WiFi(初始默认名通常是 NVRxxxxxx)。
  2. 打开命令行工具(Windows按 Win+R → 输入 cmd)。
  3. 输入这个神奇咒语(需要先安装 nmap客户端):
1
nmap -sn 192.168.254.0/24

(注意:不同型号IP段可能不同,常见的是 192.168.1.x 或 192.168.254.x)

执行后你会看到一堆设备列表,其中就有你的摄像头IP,长得像这样:192.168.254.101

此步的目的就是找到摄像头的IP

  1. 打开浏览器,输入 https://[IP地址],比如:
1
https://192.168.254.101

然后输入你在“海康互联”里设的 admin 账号密码,Boom!进入后台!

在这里你可以:

  • 查看RTSP推流地址(一般是 rtsp://admin:12345@192.0.0.64:554/h264/ch1/main/av_stream 这种格式)
  • 调整分辨率、帧率
  • 设置移动侦测报警

摄像头web界面

摄像头web界面


五、终极自由:ZLMediaKit + 百度网盘 = 永不丢失的录像库

接下来就是技术流时间(放心,不写代码):

  1. 在Mini主机安装 ZLMediaKit(搜索 GitHub 就能找到)。
  2. 配置它去拉取每个摄像头的RTSP流。
  3. 设置录制规则:比如全天录制 or 只录有人动的时候。
  4. 百度网盘客户端CloudSync 类工具,把录好的视频文件夹自动上传。

完成之后,效果是这样的:

当你出门旅游时,突然收到消息:“阳台有只野猫跳进来啃拖鞋。”
你打开手机百度网盘,翻出昨天下午三点的录像,果然看见一只橘猫正在表演“拖鞋刺身”。
你一边笑出声,一边庆幸:我没给任何公司交过一分钱会员费。

摄像头使用ZLMediaKit参考链接:https://ownding.com/2025/06/06/%E6%B5%B7%E5%BA%B7%E6%91%84%E5%83%8F%E6%9C%BA%E5%BD%95%E5%83%8F%E6%9C%BA%E5%AF%B9%E6%8E%A5%E6%96%B9%E5%BC%8F%E8%AE%B0%E5%BD%95/


六、总结:自己动手,丰衣足食

这套系统的好处总结一下:

✅ 不依赖云服务,没有月租
✅ 数据完全自主掌控,不怕泄露
✅ 支持长期存储 + 自动备份
✅ 手机随时查看,体验不输商业产品
✅ 关键是——省钱!省钱!省钱!

虽然前期稍微动了点脑子,但比起每个月被割韭菜,这点学习成本简直微不足道。


最后一句忠告:

科技应该是为你服务的,而不是让你沦为它的付费奴隶。

与其把钱交给那些天天弹窗催续费的App,不如投资一套真正属于自己的家庭安防系统。

毕竟,谁不想做一个既安全、又清醒、还不花冤枉钱的智慧家长呢?


📌 附:装备采购建议清单

名称 推荐型号 价格参考
海康摄像头 HK-Q3S5M-W / DS-IPC-K44H-LWPT ¥180~220
海康WiFi录像机 7802N-S1/W ¥60~140左右
Mini主机 Intel N100小主机 ¥300~600
开源工具 ZLMediaKit(GitHub) 免费

注意:mini主机自带几百G硬盘,够使用了。如果把录像同步到网盘后,可以清理mini主机硬盘中的视频文件。


如果你也厌倦了“云存储绑架”,不妨试试这个方案。
说不定哪天你还能靠这段拍到邻居偷摘你葡萄的视频,在小区业主群里一战成名!


#家用摄像头 #海康威视 #DIY监控 #零月租方案 #拒绝云绑架 #自己动手丰衣足食

Tailscale 4via6 在 Windows 子网路由上的 ICMP 行为说明

(为什么能用“合成 IPv6”访问 Web,却 ping -6 不通)

1. 场景与现象

  • 拓扑:
    A、B 两台 Windows 电脑安装 Tailscale;B 同时作为子网路由器(Subnet Router)。
    C 是 OpenWrt 设备,挂在 B 所在现场的内网。

  • 配置:已开启 4via6,B 宣告(advertise)一个 IPv6 子网,并在 Headscale/后台审批通过。

  • 现象:

    • 从 A 能用 “合成的 IPv6 地址” 打开 C 的 Web 服务(HTTP/HTTPS 正常)。
    • 但从 A 执行 ping -6 <C-的IPv6> 不通。抓包能看到 Echo Request 发出,但收不到回包;在 B 上用 Wireshark 看,没有 ICMP 包进入

2. 关键概念:4via6 与“合成 IPv6”

Tailscale 的 4via6 会把内网 IPv4 目标编码进一个保留的 ULA 段(如 fd7a:115c:a1e0::/48),形成合成 IPv6 地址
例:c0a8:0601 对应 192.168.6.1,于是会看到类似
fd7a:115c:a1e0:b1a0:7:c0a8:0601 这样的目的地址。

  • TCP/UDP 流量:Tailscale 会把发往这些“合成 IPv6”的包转换并送到真实的 IPv4 终端,所以浏览器/SSH/Modbus-TCP 等能正常工作。
  • ICMPv6:在 Windows 客户端 上,当前路径不会把 ICMPv6 Echo 转成 ICMPv4 Echo,因此 ping -6 不会得到回应——包也不会被转发到 B 或 C。

3. 根因(简洁版)

  1. Windows + 4via6 的协议支持面
    只对 TCP/UDP 做 IPv6→IPv4 转换;ICMPv6 不在转换范围内,所以 ping -6 失败,而 Web 正常。

  2. Windows 子网路由对“原生 IPv6 子网”的转发能力有限
    即便 B 宣告了 IPv6 子网,Windows 作为子网路由在 IPv6 转发与邻居发现处理上并不如 Linux 完整稳定,导致跨站点的 ICMPv6 转发经常不可用

    换成 Linux/OpenWrt 当子网路由后,同样配置下 ping -6 通常即可恢复正常。

4. 结论一句话

在 Windows 子网路由 + 4via6 的组合中,HTTP/UDP 能走,但 ICMPv6 不会被转换/转发,所以 ping -6 不通是预期行为;Linux 子网路由可以正常转发 ICMPv6。

5. 可选解决/替代方案

方案 A(最省事):用 IPv4 做连通性检查

  • 改用 ping 192.168.6.x(ICMPv4),或
    Test-NetConnection 192.168.6.x -Port 80/22 验证端口。
  • 适合“只想知道在线与否”的场景;无需改动现场。

方案 B(推荐):把 子网路由器 换成 Linux/OpenWrt

在 B 侧放一台小 Linux/OpenWrt 盒子(可以是现有 OpenWrt 路由或小主机/容器)作为 Tailscale 子网路由:

1
2
3
4
5
6
7
8
9
# 1) 开启 IPv6 转发
sysctl -w net.ipv6.conf.all.forwarding=1
# 持久化:/etc/sysctl.conf 里设置 net.ipv6.conf.all.forwarding=1

# 2) tailscaled 启动并宣告 IPv6 前缀
tailscale up --advertise-routes=<你的IPv6前缀>/64 --accept-dns=false
# 按需添加其它前缀,或配合 --accept-routes

# 3) 在 Headscale/管理端批准这些 routes

完成后,从 A 直接 ping -6 <C 的**原生** IPv6>,ICMPv6 会被正常转发;B 上能抓到往返的 ICMPv6。

方案 C(最干净):让 C 直接加入 Tailnet

在 OpenWrt 上安装 Tailscale,让 C 成为独立节点(拥有自己的 fd7a:... 节点地址):

1
2
3
4
5
opkg update
opkg install tailscale
/etc/init.d/tailscaled enable
/etc/init.d/tailscaled start
tailscale up

A 直接 ping -6 <C 的 Tailscale IPv6>,端到端走 Tailscale,绕开子网路由的限制。

方案 D(保留 Windows,但想要 ping -6

在 B 侧增加小型 Linux NAT64/CLAT(例如 Jool EAMT),专门把发往 fd7a:115c:a1e0::/96ICMPv6⇄ICMPv4 做转换;并在 B/网关上加静态路由把该前缀指向这台转换器。

该方案能打通 ping -6,但复杂度与维护成本较高,一般不如方案 B/C。

6. 快速排障自检

  • 能开 Web,ping -6 不通:90% 是 ICMPv6 未转换/未转发的已知限制。

  • 在 A 执行:

    • ping 192.168.6.x(C 的 IPv4):若可达,证明 4via6 通路正常,只是 ICMPv6 不支持。
    • route print -6Get-NetRoute -AddressFamily IPv6:若看到目的合成地址不断触发 Neighbor Solicitation 而无回应,这是主机把目标当“链路内”,但 Tailscale 不会为其应答/转发 ICMPv6 的典型表现。
  • 在 B 抓包(Tailscale/Wintun 接口):若看不到来自 A 的 ICMPv6,则说明包没被交给子网路由(仍印证“Windows 不处理 ICMPv6 转换”)。

7. 常见问答

  • 为什么浏览器能打开?
    因为 TCP(和大多数 UDP)会被 4via6 转换并转发到 IPv4 终端;ICMPv6 不在这个转换面里。
  • UDP 是否也能走?
    能(取决于具体协议/端口与策略),多数 UDP 通过 4via6 没问题;问题集中在 ICMPv6。
  • 以后 Windows 会支持吗?
    以当前版本看没有现成开关可启用。若对 ICMPv6 必须要,建议按方案 B/C 处理。

推荐落地选型

  • 想保留 Windows 当子网路由:接受“不能 ping -6”,用 IPv4 ping/端口探测替代。
  • 需要完整 IPv6(含 ping -6:把子网路由迁到 Linux/OpenWrt;或让终端设备直接跑 Tailscale。

openwrt

嗨,各位工业界的“键盘侠”、PLC驯兽师、设备救火队长们:

你们有没有遇到过这种尴尬场面?

👉 你想远程调试一台远在千里之外的设备,IP是 192.168.1.2 —— 很标准,很熟悉,闭着眼都能敲出来。

结果一连,连上了…隔壁老王的设备???

因为那边厂里有十台设备,清一色都是 192.168.1.2 —— 没错,工业设备出厂默认IP,就是这么“团结”。

这时候你只能:

  • 打电话问现场:“喂,老张,你那台192.168.1.2的PLC是第几台来着?”
  • 查文档:“哦对,虚拟IP是10.8.3.47…”(谁记得住啊!)
  • 改IP?不敢动,一动全厂报警,老板电话马上打过来:“你动我产线IP干嘛?!”

🤯 痛点爆炸!

别慌,救星来了!

我花了N个通宵、喝了N箱咖啡、掉了N撮头发,终于搞出了一个神器 —— 基于 WireGuide 的工业设备物联 & 远程运维系统!

它不炫技,不画饼,专治各种“IP撞车”、“远程卡壳”、“虚拟地址记不住”的工业疑难杂症。

🎯 核心功能一句话总结:

👉 你输入 192.168.1.2,我就让你连上你心里想的那台 192.168.1.2 —— 哪怕全世界有100台设备都叫这个名字!

是不是听着像魔法?其实是黑科技。

🔧 它怎么做到的?

想象一下,你走进一家超大超市,货架上摆着100瓶“可乐”,全都叫“可乐”,包装一模一样。

传统方案(比如SD-WAN/VPN)会说:“不行,重名了!我给每瓶可乐贴个编号:可乐#001、可乐#002…你得记住编号才能买。”

—— 工程师:我只想喝可乐,不想背编号!

而我的方案说:“没问题!你喊‘我要可乐’,我问你‘你要A区第三排那瓶,还是B区收银台旁边那瓶?’ —— 你指一下,我直接递给你。”

我们用 WireGuide 在后台悄悄“打标签+智能路由”,但前端完全不打扰你 —— 你看到的,还是那个熟悉的 192.168.1.2。

💡 三大爽点,专为工程师打造:

✅【零改造组网】
不用动现有设备、不用改IP、不用加交换机、不用培训网络管理员 —— 插上就能用,成本低到老板笑出声。

✅【真·原生IP访问】
PLC软件里直接输 192.168.1.2,点连接 —— 嗖,连上了!不是虚拟IP,不是映射端口,就是原汁原味的设备IP,和你在现场插网线一模一样!

✅【子网重叠?不存在的】
十台设备都是192.168.1.x?没问题!百台设备跨厂区IP全撞车?小意思!我们后台自动隔离+精准路由,互不干扰,所有设备永远在线,永不掉线。

🛠️ 举个栗子:

张工在上海总部,想调试深圳分厂的“包装机PLC”,IP是192.168.1.2。

同时,成都分厂的“注塑机PLC”也是192.168.1.2。

传统方式:张工得查表,找到“深圳包装机”的虚拟IP是10.12.5.8,再打开软件,输入这个“陌生号码”,祈祷别输错。

WireGuide方式:张工打开软件 → 选择“深圳分厂-包装机” → 自动连上 → 地址栏赫然显示:192.168.1.2 ✅

—— 就像你手机里存了两个“李伟”,一个备注“北京李伟”,一个“上海李伟”,你点“北京李伟”,打的就是北京那位。

🚀 为什么现有方案搞不定?

市面上的SD-WAN、工业VPN,本质是“换IP方案” —— 把冲突的IP换成不冲突的虚拟IP。这就像给每个人发个工牌号,不让叫名字了。

问题是:工程师不是网管!他们熟悉的是设备本体IP,不是你分配的“虚拟工号”。每次调试都要查表、换IP、重配软件 —— 效率拉胯,体验稀碎。

我的方案:不换IP,不改习惯,只改“背后怎么送信” —— 让网络自己变聪明,用户无感。

📈 效果如何?

  • 远程调试时间缩短 60%+
  • 工程师培训成本归零(因为不用学新IP)
  • 现场断网/误操作风险下降 90%
  • 老板满意度 ↑↑↑(因为不用买新设备、不用请外援、不用停产)

🎁 彩蛋功能:

  • 支持多工程师同时访问不同“192.168.1.2”,互不干扰
  • 流量加密,安全合规,符合等保要求
  • Web控制台一键切换设备,像换电视频道一样简单
  • 支持老旧设备、非智能设备、串口转网口设备 —— 老古董也能上高速!

📣 最后说句掏心窝子的:

工业不是互联网,不能总想着“颠覆”、“重构”。工程师要的是“顺手”、“靠谱”、“别添乱”。

我的产品不追求花里胡哨,只专注一件事:

让远程运维,回归它本该有的样子 —— 简单、直接、高效。

你敲 192.168.1.2,我就给你 192.168.1.2。

不多不少,不偏不倚。

如果你受够了“IP撞车”、“虚拟地址背诵大赛”、“远程调试像解谜游戏”…

欢迎来找我聊聊 👋 可以通过左侧导航栏Github链接找到我。

我们的产品让工业远程运维,像在家上路由器后台一样轻松。

#工业物联网 #远程运维 #PLC调试 #工业4.0 #WireGuide #子网冲突终结者 #工程师友好型产品 #别再背虚拟IP了

网站介绍

国内要充值 国外一些网站的会员服务,一般都挺麻烦的。

我自己有 wise ,但是基本上也很少用它来充值,主要是价格比较贵(基本上都是原价)。而且我都在 新加坡 区域充值,价格好像比其它区域更贵一点。

23年的时候有充值过 OpenAI 的 API,但是用的少,后面就没有充值了。 之后主要使用免费的比如 GeminiQwen,最近想使用下 Codex 看下效果。无意间看到有拼团的充值网站,价格比较优惠,比原价便宜 2美元。

想着就试下,发现能正常使用。 所以写出来分享下。整个操作基本没难度,直接使用 支付宝 进行付款就行。

网站是FamilyPro

FamilyPro 助您节省 ChatGPT、Netflix、Spotify 等服务费用。 分享您的订阅或加入群组——简单、安全、实惠。

链接:https://familypro.io?invite=GHb1a30b

注册、购买

推荐使用 Google 账号,我使用 hotmail 和 outlook 后缀的邮箱都不行。hotmail后缀的邮箱在注册时就提示无法使用,outlook的邮箱一直收不到 激活邮件。

该网站支持 拼团共享账号,我买的是独享,使用的是自己的账号。

如果购买独享账号,需要提供给 网站 session,然后等几分钟就能成功。我后面看了下,应该是从 iOS 端购买的。

ChatGPT登入后,session 获取地址:https://chatgpt.com/api/auth/session

主页提供多种账号充值购买!

主页

购买界面,支持支付宝!

支付宝

订单界面!

订单

OpenAI ChatGPT显示 Plus订阅成功!

订阅成功

在 iOS 端查看订阅信息!

iOS

问题

使用jenkins对一个前端项目进行打包,每次打包都出现 file-saver 超时(TIMEOUT)问题。即使将yarn依赖源改成国内都解决不了。

1
2
3
error An unexpected error occurred: "https://raw.githubusercontent.com/eligrey/FileSaver.js/e865e37af9f9947ddcced76b549e27dc45c1cb2e/package.json: ETIMEDOUT".
info If you think this is a bug, please open a bug report with the information provided in "/var/jenkins_home/workspace/frontend_k8s/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.

鉴于国内对GITHUB访问时断时续的情况,如果打包时还是从GITHUB进行下载,那么这个问题就会一直出现。

那么,在已经将yran源改成国内的情况下,为何还会出现从 GITHUB 下载的情况呢? 而且项目中 FileSaver 使用的 代码形式的引入,没有进行依赖配置。

排查

为了排查问题,我先在本机电脑上使用 VPN,然后执行 yarn install 看下 yarn.lock 情况。

在命令成功执行后,打开 yarn.lock 文件,搜索 file-saver 找到了原因。

原来是程序中使用了 jspdf,而这个组件依赖 file-saver ,而且指定从 GITHUB 下载。

至此总算找到原因了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
jspdf@^1.5.3:
version "1.5.3"
resolved "https://registry.npmmirror.com/jspdf/-/jspdf-1.5.3.tgz#..."
integrity sha512-J9X76xnncMw+wIqb15HeWfPMqPwYxSpPY8yWPJ7rAZN/ZDzFkjCSZObryCyUe8zbrVRNiuCnIeQteCzMn7GnWw==
dependencies:
canvg "1.5.3"
file-saver eligrey/FileSaver.js#1.3.8 # ← 这里是问题所在
html2canvas "1.0.0-alpha.12"
omggif "1.0.7"
promise-polyfill "8.1.0"
stackblur-canvas "2.2.0"


file-saver@1.3.8, "file-saver@github:eligrey/FileSaver.js#1.3.8":
version "1.3.8"
resolved "https://codeload.github.com/eligrey/FileSaver.js/tar.gz/e865e37af9f9947ddcced76b549e27dc45c1cb2e"

jspdf

filesaver

解决

package.json 文件中,添加 resolutions:

1
2
3
4
5
{
"resolutions": {
"**/file-saver": "^2.0.5"
}
}

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"name": "xxx",
"version": "1.0.2",
"private": true,
"author": "8080@gmail.com",
"scripts": {
// ... 你现有的 scripts
},
"dependencies": {
// ... 你现有的 dependencies
},
"devDependencies": {
// ... 你现有的 devDependencies
},
"resolutions": {
"**/file-saver": "^2.0.5"
},
// ... 其他配置
}

然后删除 yarn.lock 后,重新执行:yarn install.

背景

在很多工厂的实际网络环境中,由于历史原因,经常会出现多个子网IP地址重复(子网重叠)的问题。但由于工业生产的特殊性,我们无法对工厂现有网络进行大规模改造——一旦改动网络,可能导致生产线停机,造成严重损失。

此外,许多工业设备(如PLC、传感器等)自带TCP/IP功能,其IP地址是固定的,无法修改;部分设备端口也固定,且仅支持IPv4。这些限制进一步加剧了网络管理的难度。

当设备出现故障需要诊断时,工程师通常必须亲临现场。如果工厂距离研发中心上千公里,在生产高峰期派人出差,不仅耗时耗力,还会影响生产效率。

目前虽然有一些组网方案,比如使用NAT等,但效果并不算理想,因为工程师需要记住各种对应的虚拟地址。之前我们一直使用传统VPN解决设备远程维护的问题,但发现无法让所有子网中的设备同时在线,通信受限,实用性无法达到预期效果。而且很多工程师习惯用原始IP(如192.168.1.3)直接访问设备,不喜欢记虚拟地址或复杂域名,操作体验差。

子网重叠

解决

为了解决这些问题,我花了数月时间研究并实现了一套可行方案,满足以下核心需求:

  • 不改变工厂原有网络结构:无需调整现场设备IP或网络配置,避免影响生产。

  • 全设备在线、互联互通:所有子网设备均可接入,按需通信,也可灵活隔离。

  • 集中数据采集:只需在一台上位机安装采集软件,即可获取所有设备的数据。

  • 使用原IP远程访问:工程师可直接通过设备原有的IP地址(如192.168.1.3 或 127.0.0.1)进行远程连接和程序调试。

  • 支持相同IP设备区分访问:即使两个不同工厂都有IP为192.168.1.8的设备,也能准确指定并连接目标设备,且不影响其他设备的数据采集。

  • 贴合工程师操作习惯:尽量保持现有操作方式,降低学习成本,提升使用效率。

经过反复测试,该方案已在工业网关(带数据采集功能)和用户电脑上成功验证并使用,支持国内与海外设备的组网需求。相比早期的VPN方案,现已升级为基于 WireGuard + 自研技术 的组合方案,有效解决了子网重叠和原IP远程访问的核心痛点。

如您所在企业正面临类似问题,欢迎联系沟通,可提供完整解决方案及技术支持(包括方案购买、部署协助等)。

视频演示
说明:重叠的子网是 192.168.6.0/24。 为了能够访问,需要告诉程序你当前要访问的是哪个子网的设备,并且不能妨碍已构建设备网络的通信。

说明

本文介绍如何使用 headscaleDNS 功能。当用户使用tailscale 客户端登入后,除了可以使用 IP 进行设备互访外,还可以使用 主机名 进行设备通信。
windows 系统中,tailscale客户端登入后会在 C:\Windows\System32\drivers\etc 目录下 hosts 文件中写入 设备IP 以及 主机名,这样用户就可以使用主机名或MagicDNS进行设备互访。

功能开启

config.yaml 中,修改 dns 的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
dns:
# Whether to use [MagicDNS](https://tailscale.com/kb/1081/magicdns/).
magic_dns: true

# Defines the base domain to create the hostnames for MagicDNS.
# This domain _must_ be different from the server_url domain.
# `base_domain` must be a FQDN, without the trailing dot.
# The FQDN of the hosts will be
# `hostname.base_domain` (e.g., _myhost.example.com_).
base_domain: example.com

# Whether to use the local DNS settings of a node (default) or override the
# local DNS settings and force the use of Headscale's DNS configuration.
override_local_dns: false

# List of DNS servers to expose to clients.
nameservers:
global:
- 1.1.1.1
- 1.0.0.1
- 2606:4700:4700::1111
- 2606:4700:4700::1001

# NextDNS (see https://tailscale.com/kb/1218/nextdns/).
# "abc123" is example NextDNS ID, replace with yours.
# - https://dns.nextdns.io/abc123

# Split DNS (see https://tailscale.com/kb/1054/dns/),
# a map of domains and which DNS server to use for each.
split:
{}
# foo.bar.com:
# - 1.1.1.1
# darp.headscale.net:
# - 1.1.1.1
# - 8.8.8.8

# Set custom DNS search domains. With MagicDNS enabled,
# your tailnet base_domain is always the first search domain.
search_domains: []

# Extra DNS records
# so far only A and AAAA records are supported (on the tailscale side)
# See: docs/ref/dns.md
# extra_records: []
# - name: "grafana.myvpn.example.com"
# type: "A"
# value: "100.64.0.3"
#
# # you can also put it in one line
# - { name: "prometheus.myvpn.example.com", type: "A", value: "100.64.0.3" }
#
# Alternatively, extra DNS records can be loaded from a JSON file.
# Headscale processes this file on each change.
extra_records_path: /var/lib/headscale/extra-records.json

注释掉 extra_records: [] ,然后取消 extra_records_path 注释,使用 extra-records.json 文件作为扩展方便 headscale 发现 dns 变化。

extra-records.json 内容如下:

1
2
3
4
5
6
7
[
{
"name": "192-168-6-1-via-7",
"type": "AAAA",
"value": "fd7a:115c:a1e0:b1a:0:7:c0a8:601"
}
]

type 支持 AAAAAA 表示 ipv4,AAAA 表示 ipv6。
此项功能在开启 4via6 功能后特别好用,因为不需要去记 ipv6 地址,方便设备访问。

比如我有一台设备的 IP 是 fd7a:115c:a1e0:b1a:0:7:c0a8:601 ,这串 ipv6 地址很长不好记,那么我就可以用它对应的 ipv4 地址 作为 dns 信息。

注意 第一次修改 extra_records 配置时请先停止 headscale ,修改完后再重启。后续只需要修改 extra-records.json 即可,无需重启 headscale

使用

tailscale 客户端登入后,系统路由表中新增相关 headscale 服务端的路由。

路由

使用 192-168-6-1-via-7 访问 设备服务。

dns使用

Headscale官方的镜像大小使用docker images查看时发现只有 80M,如果我们自己使用 Dockerfile 打包镜像,发现会很大。

但是源码中给的Dockerfile文件都没法实现官方镜像的大小(毕竟是开发环境打包的),然后我就去找官方镜像是怎么打包的,在dockerhub里发现ko工具的身影,所以就尝试用ko打包headscale镜像。

ko 是一个用于构建和打包 Go 应用程序的轻量级工具,特别适用于容器化环境(如 DockerKubernetes),目标是简化 Go 程序构建为容器镜像的过程,无需编写 Dockerfile

ko 安装

我使用的 Ubuntu24.04 系统,在普通用户下安装了 go 程序。
使用 go 安装 ko

1
go install github.com/google/ko@latest

安装后,在用户目录下可以找到ko文件,我的电脑在 /home/Users/go/bin/ko 位置。

ko 打包

在源码目录下运行命令:

1
2
3
4
# --local 表示不推送镜像到仓库
/home/djc/go/bin/ko build --local ./cmd/headscale

# 打包完成后会出现 ko.local 开头的镜像
1
2
3
4
5
6
7
8
9
# 打包完成后,使用 docker images 即可查看镜像
djc@jetron-djc:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
headscale v0.26.1-r bf66da388ca1 6 days ago 87.5MB
ko.local/headscale-f40b3d8640713cd381403459ebd67e78 38aefca56cab7d9b11692c61968915fb59fdf1dce134e52fed02ae2fa3a0e871 bf66da388ca1 6 days ago 87.5MB
ko.local/headscale-f40b3d8640713cd381403459ebd67e78 latest bf66da388ca1 6 days ago 87.5MB
ghcr.io/juanfont/headscale v0.26.1 b9e7b75fd3b0 N/A 80.8MB

# 后面使用 docker tag 可重命名镜像名称

镜像运行

程序运行需要config.yaml配置文件,以及/var/run/headscale//var/lib/headscale/ 目录的读取写入权限。

1
2
3
4
5
6
7
8
# 可在 config.yaml 中将
unix_socket: /var/run/headscale/headscale.sock

# 修改成
unix_socket: /var/lib/headscale/headscale.sock

# 然后只需要挂载 /var/lib/headscale/ 目录即可运行
docker run -d -v .headscale/config.yaml:/etc/headscale/config.yaml -v ./doc:/var/lib/headscale --name headscale -p 8080:8080 -p 9090:9090 headscale:v0.26.1-r serve

参考

源码编译:https://ownding.com/2025/07/30/%E4%BD%BF%E7%94%A8Headscale%E6%BA%90%E7%A0%81%E8%87%AA%E8%A1%8C%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85/

方法介绍

有两种方法能够获取到EMQX的设备是否在线:

  • 使用 EMQX 提供的 REST API,通过API获取设备状态
  • 订阅EMQX的系统主题,当设备上线、下线时通过该主题都会收到设备上下线消息

订阅系统主题

EMQ X提供上下线状态主题:
上线主题:$SYS/brokers/<node>/clients/<clientid>/connected

下线主题:$SYS/brokers/<node>/clients/<clientid>/disconnected

1)其中 <node><clientid> 分别指定具体节点名、设备ClientID

2)支持 +#通配符

通配符模式主题: $SYS/brokers/+/clients/+/+

示例:

  • 1、配置ACL规则,可使用ip也可以用username,使得某个用户或IP能够订阅系统主题。

ACL

ACL1

  • 2、订阅主题。 我使用的是MQTTX工具进行订阅模拟。

sub

0%