Tailscale 组网架构大升级:一个出口节点,让手机告别梯子与内网的二选一

中继带宽 3.8 倍提升 + Exit Node 透明代理,出门再也不用来回切换

Posted by Marlin on October 6, 2026

⚠️ AI 生成标识 · 本文由 AI Agent 协助撰写,人类作者审核发布。

痛点:手机上的梯子和内网服务,永远二选一

用 Tailscale 组了个人网络之后,一个长期痛点困扰着我:安卓手机一次只能开一个 VPN。

安卓的 VpnService API 只允许创建一张 TUN 虚拟网卡,所以:

  • 开梯子 App → 能上外网,但连不了家里的内网服务(NAS、服务器、监控)
  • 开 Tailscale → 能访问家里内网,但上不了外网(Google、YouTube 全被墙)

出门在外,我只能在两个 App 之间来回切换,一天折腾无数次。更别提移动网络下 Tailscale 打洞失败,还得忍受绕地球半圈的中继延迟。

这篇文章记录我的组网架构大升级:如何用一个”出口节点”同时解决”回家 + 翻墙”两个需求,顺便把中继带宽提升了 3.8 倍。

Part 1:中继带宽升级——先测速,别猜

现状:5Mbps 中继是瓶颈

我的 tailnet 有 8 台设备,主力中继节点是一台 5Mbps 小带宽服务器。打洞失败的设备(手机在移动网络下几乎必失败)要走 DERP 中继,实测:

1
iperf3 -c <节点IP> -p 5201 -t 20

结果:标称 5Mbps,实际只有 3.5Mbps——中继要转发流量,实际吞吐比标称低 30% 以上。这速度连 720p 视频都卡。

升级:高带宽中继节点 + 设备偏好

加了一台高带宽服务器当中继节点后,实测 13.5Mbps(快 3.8 倍)。但 Tailscale 客户端默认选延迟最低的节点,并不会自动用高带宽那个。解决方案是设备级偏好命令:

1
sudo tailscale debug force-prefer-derp <RegionID>

它是运行时命令,重启失效,所以用 systemd 持久化:

1
2
3
4
5
6
7
8
9
10
11
12
13
# /etc/systemd/system/tailscale-prefer-derp.service
[Unit]
Description=Force Tailscale DERP preference
After=tailscaled.service
Wants=tailscaled.service

[Service]
Type=oneshot
ExecStart=/usr/bin/tailscale debug force-prefer-derp 901
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

兜底验证:主节点挂了不断网

升级过程中还发现高带宽节点一直”拒客”(derper 容器 socket 挂载失效,身份校验失败),修好后做了个关键实验:强制偏好高带宽节点,然后直接停掉它的容器——

1
2
pong from server via DERP(jdy-tj) in 19ms
direct connection not established

结论:force-prefer-derp 是”偏好”而非”锁定”——首选节点不可达时,客户端自动 fallback 到 DERP map 里的其他节点。也就是说”高带宽为主 + 低带宽兜底”天然成立,不用写任何监控脚本。

Part 2:出口节点——手机的一键解决方案

思路:让手机”回家 + 翻墙”一体化

既然安卓只能开一个 VPN,那就让 Tailscale 一个 App 干两件事:

1
2
3
4
5
6
7
手机(只开 Tailscale)
  ↓ Tailscale 隧道(优先走高带宽中继)
家庭服务器(Exit Node 出口节点)
  ↓ iptables 透明代理重定向
代理软件(Clash 系,规则分流)
  ↓ 国内直连 / 国外走代理节点
外网

出口节点配置(家庭服务器侧)

家庭服务器宣告出口并批准路由(管理后台):

1
sudo tailscale up --advertise-exit-node

流量接管靠 iptables——把从 Tailscale 接口进来的流量重定向到本地代理的透明端口(redir-port),DNS 也交给代理的 fake-ip 处理:

1
2
3
4
5
6
7
8
9
10
11
12
iptables -t nat -N EXIT_PROXY
# 内网/保留/Tailscale 网段直连(不代理)
for net in 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 \
           172.16.0.0/12 192.168.0.0/16 100.64.0.0/10 \
           224.0.0.0/4 240.0.0.0/4; do
  iptables -t nat -A EXIT_PROXY -d "$net" -j RETURN
done
# TCP → 代理透明端口;DNS → 代理 fake-ip
iptables -t nat -A EXIT_PROXY -p tcp -j REDIRECT --to-ports 7893
iptables -t nat -A EXIT_PROXY -p udp --dport 53 -j REDIRECT --to-ports 53
# 只作用于 Tailscale 接口进来的流量
iptables -t nat -A PREROUTING -i tailscale0 -j EXIT_PROXY

手机端:一个开关搞定

手机 Tailscale App 里点一下 marlin-server → Use as exit node,然后关掉梯子 App——以后:

  • 国内 App:走家里出口 IP(在外的体验和在家一样)
  • 国外流量:自动走代理节点翻墙
  • 家里内网服务:照常访问

再也不用切换梯子。

事故插曲:在 Docker 主机上启用 Exit Node 的坑

升级过程中我踩了一个差点把整个基础设施搞没的坑,必须单独记录:

在”运行 Docker 的服务器”上启用 exit node(作为客户端)会导致全容器断网。

Tailscale 启用 exit node 时,会把本机所有本地网段(恰好覆盖全部 Docker bridge 网段 172.16.0.0/12)连同默认路由写进独立路由表 52,而策略路由 ip rule 5270 优先级高于 main 表:

1
2
3
ip route get 172.18.0.3
# 故障时:172.18.0.3 dev tailscale0 table 52   ← 被劫持进隧道黑洞
# 正常时:172.18.0.3 dev br-xxxx src 172.18.0.1

所有发往容器的流量被丢进隧道、永不到达本地 bridge——我自己的 AI Agent 也因此失联(它走本地代理,代理指向容器)。修复只需一条命令:

1
sudo tailscale set --exit-node=

预防:Docker 主机上如需启用 exit node,加一条防护规则让 Docker 网段走 main 表:

1
ip rule add to 172.16.0.0/12 lookup main priority 5269   # 优先级高于 5270

架构升级前后对比

维度 升级前 升级后
中继带宽 5Mbps(实测 3.5Mbps) 13.5Mbps(快 3.8 倍)
高带宽节点挂了 走国外节点(150ms+) 自动切回低带宽兜底(不断网)
手机梯子与内网 二选一,来回切换 一个 Tailscale 全搞定
手机在外访问内网 打洞失败绕地球 高带宽中继直连
手机外网访问 依赖梯子 App 出口节点自动分流

总结

这次架构升级解决了三个实际问题:

  1. 带宽:标称 ≠ 实际,用 iperf3 测速后用 force-prefer-derp 让设备偏好高带宽中继,3.8 倍提升
  2. 兜底:force-prefer-derp 是”偏好”不是”锁定”,主节点挂了自动 fallback,网络不断
  3. 手机痛点:一个 Exit Node 出口节点 + 透明代理,让安卓手机单 TUN 限制下同时获得”回家 + 翻墙”能力,从此告别梯子与内网的二选一

最后一条教训留给你:生产环境上任何”临时测试命令”都可能瞬间让整个基础设施失联——对网络路由变更保持敬畏,Docker 主机上尤其如此。


本文所有命令均在 Linux 环境验证。Tailscale 版本 1.102.x。