把 Tailscale 从业务机拆出来:独立网关的子网路由与 Exit Node

把 Tailscale 从业务机拆出来:独立网关的子网路由与 Exit Node

我之前已经写过一篇关于 Tailscale 的文章,更多是「为什么用它、怎么工作的、配合局域网 DNS 的体验」这类方案介绍。

这次再写一篇,是因为我把部署方式做了调整:

  • 之前:Tailscale 跑在“业务服务器”上(同时承载服务)
  • 现在:单独做一台 独立 gateway,把网关职责(Subnet Router / Exit Node / NAT)和业务服务隔离

这么做的核心诉求是:

  • 网关只做网关,故障域更小;业务服务折腾升级时,不影响远程回家路
  • 网络规则(转发/NAT)集中在网关,排障更直观

文中涉及网段、接口名、主机名等均使用示例/占位符,你需要按自己的环境替换。


一、我想解决什么问题?

我希望从外网访问家里的服务,但不想:

  • 开公网端口(安全风险)
  • 配置复杂的端口映射
  • 依赖不稳定的第三方穿透

因此我的目标是:不暴露公网的前提下,在外网能像在家里一样访问局域网。

这次用「独立网关」落地后,希望达到:

  • 外网访问整个家庭 LAN(示例:192.168.x.0/24
  • 网关具备 Exit Node 能力(按需开启,不默认)
  • 重启后规则不丢(NAT/转发持久化)
  • 避免“到期就失联”的隐患(控制台策略确认/定期检查)

二、网络架构

1
2
3
4
5
6
7
[外部设备(Tailscale 客户端)]
|
v
[Tailscale 虚拟网络]
|
v
[独立网关(Ubuntu VM:Subnet Router + Exit Node)] <--LAN--> [家庭局域网(例如 192.168.x.0/24)]

这台网关负责:

  • Subnet Router:把家庭 LAN 宣告给 Tailnet
  • Exit Node:让外部设备按需走“家里出口”
  • NAT 网关:让出口流量能正确从家庭网络出站

业务服务器不再承载网关职责,只专注跑服务。


三、基础环境

  • 虚拟化平台:Proxmox
  • 网关系统:Ubuntu Server VM
  • 出口网卡:<WAN_IFACE>

四、安装与 systemd 服务

这次我用 tgz 手动安装(而不是 apt),主要是可控和省心:

  • 安装过程更可预期
  • 依赖更少,减少“仓库/镜像不通”的变量

1. 拷贝二进制

1
2
3
sudo cp tailscale tailscaled /usr/local/bin/

tailscale version

2. 修复 systemd 服务路径

tgz 自带的 service 文件有时默认写的是 /usr/sbin/tailscaled,但我实际放在 /usr/local/bin/tailscaled

检查并修正:

1
sudo nano /etc/systemd/system/tailscaled.service

确保类似字段正确:

1
2
ExecStart=/usr/local/bin/tailscaled
ExecStopPost=/usr/local/bin/tailscaled

3. 启动服务

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable --now tailscaled
systemctl status tailscaled

五、子网路由(Subnet Router)配置

1. 开启 IP Forward(关键)

1
2
3
4
5
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-tailscale.conf
sudo sysctl --system

cat /proc/sys/net/ipv4/ip_forward
# 期望输出:1

2. 宣告子网

<LAN_CIDR> 替换成你的内网网段(示例:192.168.x.0/24):

1
2
3
sudo tailscale up \
--advertise-routes=<LAN_CIDR> \
--accept-dns=false

然后在 Tailscale Admin Console 里 Approve route。


六、Exit Node 配置

如果希望网关同时提供 Exit Node:

1
2
3
4
5
sudo tailscale up \
--advertise-exit-node \
--advertise-routes=<LAN_CIDR> \
--accept-dns=false \
--snat-subnet-routes=true

我目前的策略是:

  • 保留 Exit Node 能力
  • 不默认开启,只在公共 Wi‑Fi / 受限网络 / 需要家庭出口时启用

七、NAT 与转发:踩坑与修复

1)问题表现

  • Exit Node 看起来启用了,但实际不能作为出口
  • 开启 Exit Node 后访问外网失败

2)修复:MASQUERADE(SNAT)

1
sudo iptables -t nat -A POSTROUTING -o <WAN_IFACE> -j MASQUERADE

3)修复:允许 FORWARD

1
sudo iptables -P FORWARD ACCEPT

4)持久化(非常重要)

不持久化的后果就是:

重启 = 规则丢失 = 出口/NAT 失效

Ubuntu/Debian 可以用:

1
sudo apt install -y iptables-persistent

安装时提示保存规则请选择 YES,规则通常保存到:

  • /etc/iptables/rules.v4

八、验收(一定要做)

1)子网访问验收

外部设备连接到 Tailscale 后,尝试访问内网资源(更推荐用真实业务协议,比如 ssh/http):

1
2
# 示例
ssh <LAN_HOST>

2)Exit Node 验收

开启 Exit Node 后,访问一个“查看出口 IP”的站点,确认出口变成家庭网络的出口(此处不贴具体站点与识别信息)。


九、总结

把网关从业务服务器里拆出来,最大的收益是“远程回家的路”和业务服务解耦:

  • 业务服务升级/重启/折腾,不再影响远程访问能力
  • 网络规则收敛在网关,后续排障更集中

实操层面需要重点关注的还是这几件事:

  • tgz 安装后检查 systemd 路径
  • Exit Node 不通优先排查:IP Forward / NAT / FORWARD / 规则持久化
  • 控制台显示正常不代表真通:一定要用真实流量验收