Skip to content

Tailscale 子网路由:经网关访问局域网设备

仲灏2026-06-26约 1 分钟

背景

家里 homelab 常见一堆没法或不想装 Tailscale 的设备:NAS、打印机、摄像头、内网管理面板、只监听局域网的 HTTP API 等。出门时笔记本/手机已在 Tailnet 里,希望能像在家一样访问 192.168.x.x,又不必把每个服务暴露到公网。

做法是 子网路由(Subnet Router):选一台常开、接在家里的机器当网关,把整段局域网「宣告」给 Tailnet 其它成员。

这和 Exit Node 不同——后者是让整机上网走对方出口,见 Tailscale Exit Node:让内网服务器经海外 VPS 稳定出境。访问家里 NAS 或内网 API 不需要开 Exit Node。


目标架构

text
CLIENT_TS_IP   笔记本 / 手机(Tailscale 客户端)

        │  Tailscale 虚拟网

GATEWAY_TS_IP  家里常开机器(子网网关)

        │  物理局域网 HOME_LAN_CIDR(示例 192.168.1.0/24)

LAN_DEVICE_IP  NAS / 打印机 / 内网服务等
角色说明
客户端任意已登录同一 Tailnet 的设备
子网网关与目标设备在同一物理网段、建议长期在线
局网目标打印机、NAS、Docker 内网端口、管理后台等

访问方式:客户端直接访问 局域网 IP(如 http://LAN_DEVICE_IP:端口),不要把网关的 Tailscale IP 当成 HTTP 反代地址。

典型用途举例:

场景访问方式
NAS 管理https://LAN_DEVICE_IP:5001
内网 Git / CIhttp://LAN_DEVICE_IP:3000
SSH 到 Linuxssh user@LAN_DEVICE_IP
仅局域网 APIcurl http://LAN_DEVICE_IP:8080/health

第一步:在网关上宣告子网

以下以 macOS + Tailscale App 为例;Linux 思路相同(ip_forward + tailscale set --advertise-routes)。

1. 确认网关能访问目标

在网关机器上:

bash
ping -c 3 LAN_DEVICE_IP

不通先查网线 / Wi‑Fi、防火墙,与 Tailscale 无关。

2. 开启 IP 转发

macOS:

bash
sudo sysctl -w net.inet.ip.forwarding=1
echo 'net.inet.ip.forwarding=1' | sudo tee -a /etc/sysctl.conf

Linux:

bash
sudo sysctl -w net.ipv4.ip_forward=1

3. 宣告网段

192.168.1.0/24 换成你家的真实网段:

bash
sudo /Applications/Tailscale.app/Contents/MacOS/Tailscale set --advertise-routes=192.168.1.0/24

两点踩坑记录:

  1. Mac App 已连接时,用 set,不要用 up——后者可能覆盖 App 已有参数,后台仍显示「This machine does not expose any routes」。
  2. sudo tailscale 可能 command not found——sudo 的 PATH 往往不含 /usr/local/bin,请写完整路径(见上)。

4. 本地验证

bash
/Applications/Tailscale.app/Contents/MacOS/Tailscale debug prefs | python3 -c "
import sys, json
d = json.load(sys.stdin)
print('AdvertiseRoutes:', d.get('AdvertiseRoutes'))
"

期望输出含:['192.168.1.0/24'](你的网段)。

5. 管理后台批准(必做)

  1. 打开 Tailscale Admin → Machines
  2. 找到网关机器 → Edit route settings
  3. 勾选对应网段 → Save

未批准前,其它设备永远访问不到局域网 IP。

6. macOS 本地网络权限

系统设置 → 隐私与安全性 → 本地网络 → 为 Tailscale 打开权限,否则转发到局域网可能失败。


第二步:在客户端验证连通

bash
/Applications/Tailscale.app/Contents/MacOS/Tailscale status | grep 192.168.1

应出现类似:192.168.1.0/24 via <网关主机名>

bash
ping -c 3 LAN_DEVICE_IP
# 按服务类型继续测,例如:
curl -sI http://LAN_DEVICE_IP/
ssh user@LAN_DEVICE_IP

能 ping 通、端口可达,子网路由即生效。


要不要开 Exit Node?

不需要。

能力子网路由Exit Node
访问局域网 IP❌(无关)
整机上网走对方出口

仅为访问家里局网设备,不要在客户端把网关选成 Exit Node,否则无关流量也会绕路。


故障排查速查

现象可能原因处理
sudo: tailscale: command not foundsudo PATH 不含 CLI使用 App 内二进制全路径
后台「does not expose any routes」set 或未批准tailscale set --advertise-routes=... + Admin 勾选
客户端 ping 不通局域网 IP路由未批准;网关睡眠批准网段;保持网关在线
网关通、某服务不通目标防火墙 / 只监听 127.0.0.1在网关本机先测该服务
误开 Exit Node与访问局网无关客户端取消 Exit Node

示例:局网 OpenAI 兼容 API(可选)

子网打通后,若家里还有 MLX / Ollama 反代 等只监听局域网的 LLM API,用法与其它内网 HTTP 服务相同:直接访问 http://LAN_DEVICE_IP:端口,无需为 Tailscale 单独开 Exit Node。

冒烟

bash
curl -s http://LAN_DEVICE_IP:8082/v1/models

curl -s -X POST http://LAN_DEVICE_IP:8082/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "your-local-model-id",
    "messages": [{"role": "user", "content": "说你好"}],
    "stream": false,
    "max_tokens": 100
  }'

根路径若只返回 JSON 元信息、没有聊天界面,属正常——需用 API 客户端(Cursor、ChatBox 等)。

客户端易踩坑(与 Tailscale 无关)

配置项注意
Base URLhttp://LAN_DEVICE_IP:8082/v1必须带 /v1
Model/v1/models 返回的 id 完全一致
流式部分代理首包 content: null,客户端可能空白 → 关闭 Stream

curl 有正文、UI 空白时,优先查 API 配置,不是子网路由问题。


小结

  1. 选一台常在线、与目标设备同网段的机器做 Subnet Router
  2. macOS 上 tailscale set --advertise-routes + Admin 批准,比 tailscale up 更稳。
  3. 客户端访问 局域网 IP,不是网关的 Tailscale IP。
  4. 子网路由与 Exit Node 分工不同,不要混用。
  5. LLM、NAS 等只是局网上的具体服务,连通性验证通过后再排应用层配置。

延伸阅读

本文为个人 homelab 实践脱敏整理,文中 LAN_DEVICE_IPHOME_LAN_CIDRCLIENT_TS_IP 等为示例占位,请按自己的环境替换。

讨论区

欢迎留下想法与补充