这篇文章记录一个很“朴素”的诉求:我希望把 macOS 当作主力输入设备,把 Ubuntu 设备当作移动工作站与服务承载机。两台设备通过雷电网桥或同一热点互联后,Mac 侧可以像在本机一样访问 Ubuntu 上的各种站点和服务,同时不牺牲 macOS 的日常网络体验。
写在前面
不论是出差还是在办公室,在保证数据安全和私密性的前提下,我希望打开 Mac 就能够像在本地一样访问各种开发服务。
更具体一点:
- 我希望不用改 hosts 文件,不用手工维护 DNS 服务里的几十上百条域名记录
- 我希望设备之间数据联通是高效的,能用最少的时间成本做实验验证
- 我希望 Mac 少跑一些“不必要的服务”,减少兼容性与维护成本,做到“开盖打字,合盖走人”
连上雷电数据线,或者连上同一个手机 Wi-Fi 热点,一切就顺其自然发生。
硬件环境
我使用一台 MacBook Air 作为主力打字设备,不希望它承担太多后台服务,尽量维持轻量、稳定、响应快。
另外一台设备是一台安装了 Ubuntu 的移动工作站。它原本是 Windows 设备(ROG 幻 X 旧款,《便携移动工作站,端侧 AI 大模型设备折腾笔记:ROG 幻 X 和 4090 扩展坞》有提及),后来切换到 Ubuntu 并持续升级,目前系统版本为 Ubuntu 25.10。它承担的职责很明确:跑服务、跑 CI、跑各种需要 Linux 环境才能更省事的东西。
两台设备通过雷电网桥天然可以建立高速点对点网络,稳定性也很不错。我测试过不同品牌的雷电主动线与被动线,连续连接过夜第二天仍能正常工作。简单来说,雷电网桥在这个场景里是可靠的“物理基础设施”。
关于雷电连接,在之前的文章中有提到过:《廉价的全闪存雷电 NAS 折腾笔记:组网方案的选择》、《MacBook 与其他设备的低成本高性能数据传输方案(一)》、《MacBook 与其他设备的低成本高性能数据传输方案(二)》,感兴趣可以翻阅。
软件环境与目标
简单概括,这个是典型的“很多本地域名 → 同一台开发机”的场景。
Ubuntu 设备上运行了很多网站和服务,提供给内网环境使用。通过雷电网桥连接后,我会把 Ubuntu 侧固定在一个稳定的 IP,比如 192.168.123.200。macOS 侧只要在同网段即可,IP 地址本身并不重要。
这里我们不希望在任何一台设备上再绑定 hosts,维护起来太麻烦了,少一两个还行,特别多的子域名和持续迭代过程中,体验太差了。要做到只让“开发域名”走 Ubuntu 的本地 DNS,其它正常上网域名仍然走 macOS 默认 DNS,不会互相影响。整个场景类似我们的设备连接到虚拟专用网络后,获取特别的 DNS。但因为雷电网络特性,我们通常只需要一次设置就能够持续性的使用。
真正想解决的是域名维护成本:
- 不想在任意设备上维护 hosts
- 不想在 macOS 上改全局 DNS,避免影响日常网络体验
- 希望开发域名解析规则可迁移、可复制、可排错
最终想要的效果是:
- 开发域名只走 Ubuntu 的本地 DNS
- 公网域名仍然走 macOS 的默认 DNS
- 配置一次长期使用,插上雷电线/网线,连上手机Wi-Fi就能工作
核心思路是:
- Ubuntu 上跑一个轻量 DNS(dnsmasq / CoreDNS),把要用的域名(或一整个后缀)解析到
192.168.123.200 - macOS 用 “按域名分流的 DNS”(
/etc/resolver机制)把某些域名的查询定向到 Ubuntu,其它域名不动
相关概念
Split DNS 是什么
Split DNS 可以理解为“分流 DNS”。不同域名使用不同的 DNS 服务器去解析,最常见的分流方式是公网与内网分离:
- 公网域名例如
apple.com、soulteary.com,使用系统默认 DNS,通常来自运营商或公共 DNS 服务 - 内网或开发域名例如
*.dev.test、*.corp.example.com,使用内网 DNS 或本地 DNS,把域名解析到内网 IP
这样做的好处是,不影响日常上网,内网域名能稳定解析到内网 IP,不需要大量维护 hosts 文件。
本文就是第二种方案的典型应用:只让开发域名走 Ubuntu 本地 DNS,其它域名不动。
macOS 的 resolver 机制是什么
macOS 有一套系统级 DNS 解析器,也就是 resolver。它会根据配置与网络环境决定:
- 解析某个域名时该用哪一组 DNS 服务器
- 是否命中按域名分流规则
- 缓存与优先级如何处理
macOS 原生支持“按域名分流”。最容易上手的一种方式就是在 /etc/resolver/ 目录中创建配置文件,用声明式方式告诉系统:
- 某个域名后缀应当使用哪个 DNS nameserver
- 其它域名保持默认行为
另外一种,则是通过网络配置下发配置(各种公司使用的专用网络方案),后续文章我们再涉及。而 macOS 之外,其他系统也基本支持类似特性:Windows 有 NRPT(Name Resolution Policy Table);Ubuntu / Linux 中有 systemd-resolved 的路由域名,有NetworkManager 的 per-connection DNS + 搜索域,有“传统一些的” resolv.conf;Android 中有 Private DNS、以及类似 macOS 的网络下发配置方案。
所以,如果你想使用 Windows 设备、Android 平板作为打字设备,只要两台(或几台)设备联通,就能够实现一样的效果啦。
实际使用非常简单,创建一个配置文件 /etc/resolver/dev.test ,在其中设置以下内容:
nameserver 192.168.123.200
port 53
当我们访问 *.dev.test 时,这些域名的解析就会被定向到 192.168.123.200,而其他域名依旧走系统默认 DNS。
如果你依旧想使用一台设备进行本地开发域名的管理维护,那么还是可以参考下面几篇文章:《在线分享 Hosts 规则工具:Remote Hosts Server》、《用于本地开发使用的 DNS 方案》、《快速切换 Mac 设备的 DNS 配置》。
实战开始
下面以 dev.test 作为开发后缀示例。.test 是保留给测试用途的域名后缀,使用它可以避免误伤真实公网域名。需要注意的是,在 macOS 系统里 .local 会被 Bonjour mDNS 特殊处理,不建议用 .local 作为你的开发后缀。
在 Ubuntu 上安装 dnsmasq 并配置“通配解析”
在 Ubuntu 上安装 dnsmasq:
sudo apt update
sudo apt install -y dnsmasq
创建配置文件:
sudo tee /etc/dnsmasq.d/dev-domains.conf >/dev/null <<'EOF'
# 把 *.dev.test 全部指到 Ubuntu
address=/.dev.test/192.168.123.200
# 上游 DNS(避免 dnsmasq 无法解析公网域名时卡住)
server=1.1.1.1
server=8.8.8.8
# 只在本机与雷电网桥接口上监听(按需改)
listen-address=127.0.0.1,192.168.123.200
bind-interfaces
EOF
如果你希望 Ubuntu 设备内的网站的私有网络环境有单独的解析,listen-address 部分可以只填 192.168.123.200 即可。
重启服务并设置开机启动:
sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq
在 Ubuntu 上进行验证:
dig @127.0.0.1 foo.dev.test +short
# 应返回 192.168.123.200
如果你曾经在 /etc/hosts 中绑定过相关测试域名,记得删除对应记录,否则 hosts 的优先级会让你误判问题来源。
在 macOS 上为这个“开发后缀”做 DNS 分流
在 macOS 中创建 resolver 配置文件:
sudo mkdir -p /etc/resolver
sudo tee /etc/resolver/dev.test >/dev/null <<'EOF'
nameserver 192.168.123.200
port 53
EOF
刷新系统 DNS 缓存:
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
接下来进行验证。这里有一个容易踩坑的细节:
在 macOS 上,dig 往往不会完全遵循系统 resolver 的分流逻辑,所以用 dig foo.dev.test 可能会得到“看起来不对”的结果。更可靠的验证方式是让系统 resolver 亲自参与解析,例如用 ping 或 dscacheutil:
ping -c 1 foo.dev.test
如果分流生效,你会看到它解析到 192.168.123.200:
能够看到 DNS 记录已经正确了。
PING foo.dev.test (192.168.123.200): 56 data bytes
64 bytes from 192.168.123.200: icmp_seq=0 ttl=64 time=1.391 ms
也可以用 dscacheutil:
dscacheutil -q host -a name foo.dev.test
想确认系统侧到底加载了哪些 DNS 规则,可以用:
scutil --dns
如果你确实想用 dig,建议显式指定 DNS 服务器,这样你测到的是 Ubuntu DNS 的回答,而不是 macOS 默认 resolver 的选择:
dig @192.168.123.200 foo.dev.test +short
# 应返回 192.168.123.200
到这里,Split DNS 的核心配置就完成了。
常见问题与排错
这套方案很稳定,但排错时最好遵循一个顺序:先确认 Ubuntu 是否答对,再确认 macOS 是否问对。
先确认 Ubuntu 是否答对
无论 macOS 侧发生什么,先直接问 Ubuntu:
dig @192.168.123.200 foo.dev.test +short
- 如果这里都不对,优先查 Ubuntu 的 DNS 服务配置、监听地址、端口与防火墙
- 如果这里正确,再看 macOS 侧的分流是否生效
再确认 macOS 是否问对
macOS 侧优先使用系统解析器验证:
dscacheutil -q host -a name foo.dev.test
如果你看到解析结果正确,但浏览器访问仍然不对,通常是浏览器启用了 DoH 之类的“安全 DNS”绕过了系统 resolver。这个时候你需要在浏览器中关闭或改为使用系统解析器。
为什么有的子域名正常有的域名不正常
最常见的原因是“更精确的记录优先级更高”。一个典型例子是:
- 通配规则把
*.dev.test指到192.168.123.200 - 但你可能曾经在
/etc/hosts或 DNS 配置里为某个特定域名写过精确记录,例如把它指到了127.0.0.1
这会导致:
a.foo.dev.test走通配规则正常foo.dev.test因为精确记录被抢先命中,解析到你意料之外的地址
排查这种问题最简单的方法仍然是直接问 Ubuntu DNS:
dig @192.168.123.200 foo.dev.test +short
dig @192.168.123.200 a.foo.dev.test +short
如果 Ubuntu 自己答复的就是 127.0.0.1,那就说明问题在 Ubuntu 的 DNS 配置或 hosts,而不是 macOS。
最后
把开发域名解析这件事从“每次临时改 hosts”升级成“声明式分流规则”,带来的收益很直接:
- 配置一次长期可用
- 日常网络零干扰
- 开发服务迁移或增减域名几乎不再产生维护成本
- 排错路径清晰,系统边界明确
如果你也在使用两台设备协同开发,无论是雷电网桥、同一热点还是家庭局域网,只要网络可达,就可以用同样的思路把体验做得更顺滑。
–EOF