前言

之前建立了一个 [无敌小白版] WireGuard配置 但是路由器问题无法连通,后续打算用ZeroTier来配置了。

于是也就诞生了这篇文章。

正文

1. 安装 ZeroTier

树莓派上执行:

curl -s https://install.zerotier.com | sudo bash

安卓或者其他端就按照相关的安装方式去安装:ZeroTier下载。安装完成后,我们创建一个网络,在创建网络之后ZeroTier会提供一个Network ID,加入即可。

sudo zerotier-cli join <Network ID>

然后授权。

2. 开启 IP 转发

树莓派默认不会帮你转发流量,需要打开(允许树莓派在两个网卡之间“转发”流量。):

# 临时打开(重启失效)
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

# 永久打开(写进配置文件)
sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sudo sysctl -p

3. 设置 NAT(伪装内网流量)

sudo iptables -t nat -A POSTROUTING -s 10.147.19.0/24 -o eth0 -j MASQUERADE

这个网段(10.147.19.0/24)是 ZeroTier 自动分配的,每个人的可能不一样。

  • -t nat → NAT 表

  • POSTROUTING → 出口方向生效

  • -s 10.147.19.0/24 → ZeroTier 分配的虚拟网段

  • -o eth0 → 出物理网口 eth0(连着你家路由器的那个口)

  • MASQUERADE → 伪装成树莓派的 IP

4. 配置 ZeroTier Central

在 ZeroTier Central → 你的网络设置里:

添加 Managed Routes

10.147.19.0/24           (LAN)     ← ZT 内部虚拟网段
192.168.1.0/24 via 10.147.19.163   ← 通过树莓派访问家里真实的内网
0.0.0.0/0      via 10.147.19.163   ← 通过树莓派访问所有流量(全局 VPN)

含义:

  • 10.147.19.163 是树莓派在 ZeroTier 虚拟网中的地址(每个人的会不一样)。

  • 192.168.1.0/24 via 10.147.19.163 → 让手机能访问家里的内网

  • 0.0.0.0/0 via 10.147.19.163 → 让手机所有流量都走树莓派(全局 VPN)

  • 其中 10.147.19.163 是树莓派在 ZT 内网中的虚拟地址

5. 配置DNS

这里我们因为树莓派是我们的DNS内网服务器,我们想客户端连接的时候也会走 树莓派这个DNS服务器

5.1 ZeroTier Central配置DNS

  • Search Domain 我这里 填写home.lan

  • Server Address 是我们的DNS服务器地址,我这里是树莓派在ZT虚拟内网的地址,也就是 10.147.19.163

5.2 客户端配置DNS

我这里是安卓手机,我需要选择 DNS Configuration - Network DNS 就可以了,然后在Status就会发现DNS Server Addresses 是 10.147.19.163/0:

总结

大概的流程可以总结为下图:

flowchart LR %% 样式 classDef box fill:#eef,stroke:#888,rx:8,ry:8 classDef net fill:#ffe,stroke:#aa7,rx:8,ry:8 classDef gw fill:#efe,stroke:#7a7,rx:8,ry:8 classDef ext fill:#fef,stroke:#a7a,rx:8,ry:8 classDef note fill:#fffbe6,stroke:#f0c36d,stroke-dasharray:5 5,rx:6,ry:6 %% ZeroTier 虚拟网 subgraph ZT["ZeroTier 虚拟网络 (10.147.19.0/24)"] direction LR M["手机 (ZT 成员)<br/>10.147.19.34"]:::box PI_ZT["树莓派 (ZT 成员)<br/>10.147.19.163"]:::box M --- PI_ZT end %% 家庭局域网 subgraph LAN["家庭内网 <br/> (192.168.1.0/24)"] direction TB PI_LAN["树莓派 实体网口 eth0<br/>192.168.1.50"]:::gw DNS[路由器/DNS\n192.168.1.1]:::box PH["Pi-hole / 其他内网设备<br/>如 192.168.1.50/…"]:::box PI_LAN --- DNS PI_LAN --- PH end NET[Internet]:::ext %% 路由策略(Managed Routes) R1{{192.168.1.0/24\nvia 10.147.19.163}}:::net R2{{0.0.0.0/0\nvia 10.147.19.163}}:::net %% 数据流向(全局) M -- 访问内网 --> R1 R1 -.-> PI_ZT M -- 公网流量 --> R2 R2 -.-> PI_ZT %% 树莓派转发与 NAT PI_ZT ==> PI_LAN PI_LAN == NAT(MASQUERADE) ==> DNS DNS --- NET %% 说明(用注释节点代替 note) N1["开启转发:<br/>net.ipv4.ip_forward=1"]:::note N2["NAT 规则:<br/>iptables -t nat -A POSTROUTING -s 10.147.19.0/24 -o eth0 -j MASQUERADE"]:::note N3["作用:<br/>R2 让手机“全局流量”先到树莓派<br/>R1 让手机可达 192.168.1.0/24"]:::note N1 -.-> PI_LAN N2 -.-> PI_LAN N3 -.-> R2

我们的实现其实是 zt的路由树莓派的iptable + IP转发 共同的作用:

1. ZeroTier Central 的 Managed Routes

  • 0.0.0.0/0 via 10.147.19.163 → 告诉 所有加入 ZT 网络的客户端
    “如果要去任意 IPv4 地址,就先把包发到 10.147.19.163”。

    • 这里的 10.147.19.163 就是你树莓派的 ZT 虚拟 IP

    • 所以手机 / 电脑连到 ZeroTier 后,默认网关就变成树莓派

  • 10.147.19.0/24 (LAN) → 这个是 ZeroTier 自动生成的,保证虚拟网段内部互通,不需要指定网关。

  • 192.168.1.0/24 via 10.147.19.163 → 告诉 所有加入 ZT 网络的客户端
    “如果要去192.168.1.0/24 网段的地址,就先把包发到 10.147.19.163”。

所以,这里的 树莓派 其实在我们 的客户端进入到ZeroTier 之后就变成了我们的 默认网关(路由器)。

2. 树莓派上的 NAT / 转发

到这一步,流量只是到了树莓派,还没出公网。

  • 树莓派开启了 IP 转发 net.ipv4.ip_forward=1 → 它会把手机的包继续转发。

  • 树莓派上的 iptables -t nat -A POSTROUTING -s 10.147.19.0/24 -o eth0 -j MASQUERADE 这条规则:

    • 匹配 从 ZeroTier 网段 (10.147.19.0/24) 来的包

    • 出口是物理网口 eth0(连你家路由器)

    • 动作是 MASQUERADE → 把源 IP 改成树莓派的 LAN IP(比如 192.168.1.50)

这样,家里的路由器才会把这些包当成是树莓派自己发的,然后正常转发到公网。

参考

[1] ChatGPT
[2] 自己
[3] [无敌小白版] WireGuard配置 但是路由器问题无法连通
[4] ZeroTier下载

立志做一个有趣的碳水化合物。