# Tailscale Split DNS：tailnet 内直连内网服务


## 场景

家里一台服务器跑着不少服务，没有公网 IP。域名的 A 记录指向一台公网 VPS，VPS 上的 Caddy 反向代理回家庭服务器。tailnet 内的设备访问这些域名也要绕 VPS 一趟，多一跳延迟。

想让 tailnet 在线时，域名直接解析到家庭服务器的 Tailscale IP；tailnet 断开时，自动回落到 VPS 公网 IP。同一个域名，两种解析结果。

## 家庭服务器上跑一个 dnsmasq

[dnsmasq](https://github.com/thekelleys/dnsmasq) 负责应答 tailnet 内发来的域名查询，就装在家庭服务器上，应答的就是它自己的 Tailscale IP。安装后写一个配置（Arch 用 `pacman -S dnsmasq`，Debian 系用 `apt install dnsmasq`）：

```ini
# /etc/dnsmasq.d/services.conf
address=/app1.example.com/<tailnet-ip>
address=/app2.example.com/<tailnet-ip>
# 只监听 tailscale 网卡和本机
listen-address=<tailnet-ip>,127.0.0.1
bind-dynamic
# 显式指定上游，绕过 tailscale 的 100.100.100.100，防止解析环
no-resolv
server=<gateway-ip>
# 阿里云公共 DNS
server=223.5.5.5
server=223.6.6.6
```

`address=` 一行一个域名，有几个服务写几行。没写进 `address=` 的域名照常转发上游解析。

`no-resolv` 是必须的。tailscale 会把服务器的 `/etc/resolv.conf` 改成 `nameserver 100.100.100.100`。如果 dnsmasq 按默认读 resolv.conf 转发上游，加了 split DNS 之后，服务器自己解析 `*.example.com` 会发给 100.100.100.100，tailscale 的解析器又把这条查询转发回这台 dnsmasq，形成环。显式指定路由器或公共 DNS 作上游就绕开了。

启动并设为开机自启：

```bash
sudo systemctl enable --now dnsmasq
```

建议再加一个 drop-in，让 dnsmasq 排在 tailscaled 之后启动：

```ini
# /etc/systemd/system/dnsmasq.service.d/tailscale.conf
[Unit]
After=tailscaled.service
Wants=tailscaled.service
```

## 管理后台加一条 split DNS

1. 打开 https://login.tailscale.com/admin/dns
2. Nameservers → Add nameserver → Custom
3. 填家庭服务器的 Tailscale IP（`<tailnet-ip>`）
4. 域名填 `example.com`，匹配所有子域

一条规则覆盖全部子域名。之后 tailnet 内查询 `*.example.com` 都会发给这台 dnsmasq。

用了 exit node 时 split DNS 默认不生效，需要在该 nameserver 上勾选 Use with exit node。

## 证书

直连路径上，客户端直接连家庭服务器的 443 端口，TLS 必须由家庭服务器自己终结。服务器没有公网入站，证书只能走 DNS-01 质询，[Caddy](https://caddyserver.com) 配合 Cloudflare DNS-01 的做法见 [Caddy Cloudflare DNS-01：获取通配符 TLS 证书](/posts/caddy-cloudflare-dns-challenge/)。通配符 `*.example.com` 一张证书盖住所有服务，Caddy 自动签发和续期。

## 验证

Windows 上分别开、关 tailscale 各跑一次：

```powershell
nslookup app.example.com
```

tailscale 开着应返回 `<tailnet-ip>`，关掉后返回 VPS 公网 IP。结果没变就 `ipconfig /flushdns` 清一次缓存。

dnsmasq 对本地配置的应答 TTL 为 0，客户端不缓存，切换即时生效。公共记录那边的 TTL 也可以调低（比如 60 秒），减少回落侧的缓存滞后。浏览器开了 Secure DNS（DoH）会绕过本地解析器，这些域名会一直走公共 DNS 的 VPS 链路，功能不受影响，只是不直连。


---

> 作者: Nite  
> URL: https://www.nite07.com/zh-cn/posts/tailscale-split-dns/  

