在家用宽带"封端口"时代,我如何用 Tailscale 搞定跨网络远程开发
一个”Windows Hyper-V VM + Cloudflare DDNS + 端口转发”踩坑实录,
以及为什么最后答案是一行tailscale up。(本文已对账号、IP、tailnet 名等敏感信息脱敏,仅保留技术结构。)
TL;DR
我有一台家用宽带(动态公网 IP)里的 Hyper-V Ubuntu 虚拟机,想从手机热点、
公司、任何网络随时连进去开发。我花了半天搭 DDNS + 三层端口转发,
结果外网连不进来——运营商在封家用宽带的入站端口。最后用 Tailscale
一条命令搞定,彻底绕开 DDNS、端口转发、运营商封锁。
下面是完整踩坑和最终方案。
一、目标
- 家里:Windows 宿主机跑 Hyper-V Ubuntu VM,静态内网 IP
172.x.x.x - 手机 / 任意网络:能随时 SSH 进 Ubuntu 开发
- 要求:IP 怎么变都不用管,最好不用开公网端口
二、第一套方案:DDNS + 端口转发(为什么走不通)
2.1 架构
1 | 互联网 → 光猫/路由器(动态公网IP) → Windows(192.168.x.7) → portproxy 2222 → Ubuntu VM(172.x.x.x:22) |
需要打通三层:
- Cloudflare DDNS:把
devbox.dingdao.me自动指向当前公网出口 IP - 路由器端口转发:外部
2222 → 192.168.x.7:22 - Windows portproxy:
2222 → 172.x.x.x:22+ 防火墙放行
2.2 我写的 DDNS 脚本(带容错)
1 |
|
systemd timer:开机 + 每 15 分钟跑一次。
踩坑:我一开始把 Cloudflare 控制台里的 Account ID 当成 Zone ID 填进脚本,结果 API 404。后来用 API 自动解析出 devbox.dingdao.me 所属 zone 的真实 Zone ID,脚本里直接查 API,不再手填。
2.3 为什么外网连不进来
所有配置都对:
- ✅ CF 记录
devbox.dingdao.me → xx.xx.xx.xx(当前公网出口 IP) - ✅ 服务器公网出口 IP 就是那个 IP
- ✅ Windows portproxy
2222 → 172.x.x.x:22正确,LAN 段Test-NetConnection 192.168.x.7 -Port 2222通 - ✅ 手机有公网 IPv4(测试
curl -4 https://ifconfig.me能拿到一个公网 v4,不是 IPv6-only)
但外网 xx.xx.xx.xx:2222 始终 CLOSED。
排查结论:运营商在封家用宽带入站。家用宽带(尤其 PPPoE 拨号那层)
很多地区默认拒绝非 80/443 的入站 TCP,甚至全端口拒绝。DDNS + 端口转发
这套在”运营商不封入站”的网络里是完美的,但在我家这堵墙前无能为力。
这是国内家宽的老问题,不怪配置,怪物理链路。
三、最终方案:Tailscale(出站打洞,零入站端口)
3.1 为什么 Tailscale 能绕过这堵墙
Tailscale 本质是 WireGuard + 出站打洞:
- 每台机器主动向外连 Tailscale 的 Coordination Server(UDP 443)
- 两台机器之间通过打洞建立直接 P2P WireGuard 隧道(如果打洞失败,
退化为经 Tailscale 中转 relay,也不影响可用) - 全程不需要任何入站端口,不需要 DDNS,不需要运营商放通
对你的网络意味着:哪怕家用宽带入站全封,只要能出站(上网),
Tailscale 就能通。
3.2 三端落地(同一 Google 账号 → 同一 tailnet)
1 | Ubuntu VM (Hyper-V) + Windows 宿主机 + 手机(Android/Termux) |
Ubuntu(服务器侧):
1 | curl -fsSL https://tailscale.com/install.sh | sh |
- 开机自启(
systemctl enable tailscaled) --ssh开了 Tailscale 自带 SSH,免私钥直连(控制台自动分发公钥)
Windows(宿主机):winget install Tailscale.Tailscale 或官网安装包,
同账号登录。
手机:App Store / Play 装 Tailscale,同账号登录,自动进 tailnet。
3.3 连接(任意网络、任意时刻)
本地 ~/.ssh/config(和原 DDNS 并存,双保险):
1 | Host devbox-ts |
手机(最省事,免私钥):
1 | tailscale ssh [email protected] |
3.4 验证
sudo tailscale status三端全在线- 手机
tailscale ssh kali@...直接进 Ubuntu shell ✅ tailscale ssh不走 22 端口、不走公网,运营商封多少端口都不影响
四、安全性(针对”私人文件会不会暴露”的担忧)
Tailscale 在这套场景里不增加公网攻击面,原因:
- 默认对公网不可见:
100.x.y.z是 RFC1918 保留段,公网路由送不到;
攻击者没有你的账号 + tailnet 的 WireGuard 密钥,连”敲门”都找不到 - 双向 WireGuard 加密(AES-256-GCM):流量嗅探也解不开
- 默认零开放端口:不开 Funnel、不开 Subnet Router、不开
--ad-v4;
我确认过 Funnel 是关的 - 唯一成员 = 你的 Google 账号:要进 tailnet 得先攻陷你的 Google,
那是账号层面的事,不是 Tailscale 新开的口子
真实剩余风险全在”账号/设备被攻破”层面,按性价比做这几项加固:
- Google 开两步验证(最优先)
- Tailscale 控制台开 2FA + 定期查 活跃会话/陌生设备(陌生即 revoke)
- 用 Per-Device ACL 收紧:手机/Windows 只允许连 Ubuntu 的 22,其余 deny
(即使某台设备密钥泄露,横向也被限死在 ACL 内)
五、踩坑清单(可复用)
| 坑 | 解法 |
|---|---|
| Cloudflare 的 Account ID ≠ Zone ID,填错 404 | 用 API 查 zone 列表拿真实 Zone ID,脚本自动解析 |
| DDNS 脏数据污染(IP 源全挂时把记录写空) | 全失败时保留 last_ip,绝不覆盖已有正确记录 |
| 家宽外网入站被封(DDNS+转发全对但外网 CLOSED) | 换 Tailscale 出站打洞,零入站 |
| Hyper-V VM 重启 IP 变导致 portproxy 指错 | VM 侧 netplan 配静态 IP,一劳永逸 |
| Tailscale headless 拿不到认证 URL | nohup sudo tailscale up ... & 后台跑,读 log 里的 URL |
六、一句话总结
家用宽带入站不可控(运营商封端口、光猫路由模式二级 NAT、动态 IP)
这三个坑让”DDNS + 端口转发”在家用场景下不可靠。
Tailscale 用”出站打洞”把问题降维成”只要能上网就能连”,
是个人远程开发/私人文件互通场景的默认最优解。
DDNS 那套留着做局域网直连的备用,公网访问交给 Tailscale。
配图建议:① 三层转发架构 vs Tailscale 全 mesh 对比 ② tailscale status 三端在线截图(IP 打码)③ 控制台安全加固项
脱敏说明(发文前自查)
本文已做如下脱敏,发布前请再自查一遍:
- 真实邮箱
[email protected]→ 文中已隐去(只写”同一 Google 账号”) - 真实公网出口 IP
122.231.144.252、手机出口124.160.204.98→ 文中用xx.xx.xx.xx占位 - 真实 tailnet 名
tailb889a7→ 文中用xxx占位(devbox.<tailnet>.ts.net) - 真实内网
172.31.92.47/192.168.2.7→ 文中用172.x.x.x/192.168.x.7占位 - 真实域名
kaliserver.dingdao.me/kaliserver.tailb889a7.ts.net→ 文中改为devbox.dingdao.me/devbox.<tailnet>.ts.net - Tailscale IP
100.123.36.49/100.113.231.42/100.98.143.1→ 文中用100.123.x.x/100.113.x.x/100.98.x.x占位
如需完全不可追溯到个人,上述占位符已覆盖所有可直接定位的标识符;
如需保留部分真实值(如公开博客保留域名示例),可把 devbox.dingdao.me
换成你自己愿意公开的域名。