使用 Tailscale 实现安全无公网暴露的内网访问方案

Tailscale 实现安全无公网暴露的内网访问方案

一、为什么需要内网穿透?

在家中,我有一台 Ubuntu 服务器运行了一些自建服务,比如文件同步、git仓库、影音服务等。这些服务默认只在局域网中访问,通过cosmos将内网域名绑定到对应的端口上,而域名的解析依赖家庭网关上的 OpenWrt DNS 设置。

为了方便我在外出时也能访问这些服务(如从手机查看笔记、上传照片),需要实现“内网穿透” —— 但我并不想:

  • 开公网端口(有安全风险)
  • 配置复杂的端口映射
  • 依赖第三方穿透平台(不稳定、可能收费)

最终发现 Tailscale,一个轻量、私密、安全的零配置 VPN 工具,能完美的满足需求。


二、Tailscale 的工作原理简述

Tailscale 基于 WireGuard 构建,核心特性包括:

  • 点对点加密连接(不需要公网 IP)
  • 自动 NAT 穿透
  • 设备认证与访问控制
  • MagicDNS(自动内网 DNS)
  • Subnet routing(子网路由功能)

它构建了一个虚拟的 overlay 网络,给每个设备分配一个 100.x.x.x 的 IP,你可以像在同一局域网一样访问其他设备。

你还可以通过 --advertise-routes 把整个局域网广播给 Tailscale 网络中的其他设备,让一台设备成为“桥梁”,访问更多子网资源。


三、我的网络架构与实现目标

1
2
3
4
5
6
[手机(Tailscale 客户端)]
|

[Tailscale 虚拟网络]

[Ubuntu 服务器(Tailscale 节点 + 子网网关)] ←LAN→ [OpenWrt 路由器(本地 DNS)]
  • Ubuntu 是唯一连接到 Tailscale 的设备,它是子网网关
  • OpenWrt 提供 DNS 解析,但无法安装 Tailscale
  • Android 手机使用域名访问服务(例如 http://server.home.local
  • 目标:手机可以在任意网络下访问局域网服务,无需公网映射

四、Ubuntu 上的 Tailscale 配置步骤

1. 安装 Tailscale

1
curl -fsSL https://tailscale.com/install.sh | sh

2. 启用子网路由

1
2
3
4
sudo tailscale up \
--advertise-routes=192.168.100.0/24 \
--accept-dns=false \
--accept-routes

3. 开启 IP 转发 + NAT

创建脚本 /usr/local/bin/tailscale-nat-bridge.sh

1
2
3
4
5
6
7
#!/bin/bash
sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-tailscale-forward.conf
sysctl --system

iptables -t nat -D POSTROUTING -s 100.64.0.0/10 -d 192.168.100.0/24 -j MASQUERADE 2>/dev/null
iptables -t nat -A POSTROUTING -s 100.64.0.0/10 -d 192.168.100.0/24 -j MASQUERADE

配置 systemd 自启动服务:

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=Enable IP forwarding and NAT for Tailscale
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/tailscale-nat-bridge.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

五、Tailscale 控制台的 Split DNS 设置

进入 Tailscale DNS 控制台

  1. ✅ 启用 MagicDNS
  2. ➕ 添加 Split DNS 设置:
    • DNS Server: 192.168.100.1(OpenWrt 的 IP)
    • Search domain: home.local
  3. Android 客户端设置中启用「使用 Tailscale DNS」

这样,访问 server.home.local 会自动从 OpenWrt 解析出正确的局域网 IP。


六、OpenWrt 上的 DNS 配置

确保 OpenWrt 的 dnsmasq 设置了正确的本地域名,例如:

1
2
/etc/hosts:
192.168.100.10 server.home.local

或者在 /etc/config/dhcp 中使用 config domain 显式定义。

如果 OpenWrt 启用了防火墙规则限制 DNS 接入,可以添加:

1
2
3
4
5
6
7
8
9
uci add firewall rule
uci set firewall.@rule[-1].name='Allow-DNS-from-Ubuntu'
uci set firewall.@rule[-1].src='lan'
uci set firewall.@rule[-1].src_ip='192.168.100.10'
uci set firewall.@rule[-1].dest_port='53'
uci set firewall.@rule[-1].proto='tcp udp'
uci set firewall.@rule[-1].target='ACCEPT'
uci commit firewall
/etc/init.d/firewall restart

七、排错记录与 Android 端的坑

问题 1:DNS 无法解析域名

  • 原因:虽然配置了 Split DNS,但 Android 默认不会使用 Tailscale 分配的 DNS
  • 解决:手动启用「使用 Tailscale DNS」选项,并断开重连 Tailscale

问题 2:Termux 中 nslookup 不生效

  • 原因:Termux 不使用 Android 系统 DNS 设置
  • 解决:测试时手动指定 DNS,比如:
    1
    nslookup server.home.local 192.168.100.1

问题 3:OpenWrt DNS 无法响应请求

  • 原因:它只能服务局域网,不允许 Tailscale 网段访问
  • 解决:在 Ubuntu 上开启 IP 转发 + NAT,并允许访问 192.168 网段

八、最终访问效果

  • ✅ 手机可在任意网络下访问 http://server.home.local
  • ✅ 不需公网映射,不暴露任何服务端口
  • ✅ 整体体验就像在家中访问局域网一样自然

九、总结与延伸建议

本方案只需一台 Ubuntu 作为桥梁,无需改动路由器结构,适合:

  • 希望远程访问家庭服务但不想暴露公网端口的人
  • 拥有局域网 DNS、自建服务需求的用户
  • 在乎安全、隐私和轻量 VPN 架构的技术用户

延伸功能可探索:

  • 使用自签名 HTTPS + tailscale 提供的 TLS
  • Tailscale ACL 权限限制
  • 使用 Tailscale Funnel 实现临时公网服务(如分享临时链接)

Tailscale 真正做到了 “内网穿透的尽头是 VPN”。而且是一个“聪明、自动、私有”的 VPN。

希望这篇分享对你有所帮助!