出差住酒店、在咖啡馆蹭网,DNS 这层基本没法管。想自己跑个 Pi-hole,又得先备树莓派、装 Docker、配一堆东西,为了个解析器折腾半天。最近刷到一个项目 Numa,思路挺讨巧:把一个够用的 DNS 服务器压成约 8MB 的单文件二进制,装完往包里一揣,走到哪儿跟到哪儿。

38 万条广告,走哪拦哪

它是什么

Numa 是 razvandimescu 用 Rust 从零写的 DNS 解析器。有意思的是它连现成的 DNS 库都没用,报文解析器是手写的,后来才陆续补上递归解析、DNSSEC 和 Web 面板。GitHub 上目前 1.5k+ star,还在高频更新。

它的定位一句话就能说完:DNS you own, everywhere you go——自己的 DNS,走到哪带到哪。单个二进制、资源全内置,不需要云端账号,也不需要一台 7×24 常开的树莓派。

装法也够散装:macOS 走 Homebrew,Linux 一条 install.sh,Arch 直接 pacman -S numa,Windows 下 Releases 里拿 exe,哪个平台都能 cargo install numa。

装完能干的三件事

一、广告拦截,换个网络照样拦

  • 规则用的是 Hagezi Pro,38 万多条域名,每天自动刷新
  • 关键是跟机器走:酒店、机场、咖啡店的 Wi-Fi 一样生效,不用碰路由器
  • 拦截发生在本地,不用把查询交给第三方清洗

这一点和 Pi-hole 的差别很实在——Pi-hole 是「网关门神」,你得待在那个网络里;Numa 更像「随身过滤器」,笔记本在哪,拦截就在哪。

二、本地域名 + 自动 HTTPS 绿锁

开发时最烦的就是记端口。Numa 给了个很轻的解法:

1
2
curl -X POST localhost:5380/services \
-d '{"name":"frontend","target_port":5173}'

之后浏览器打开 https://frontend.numa 就行,证书自动签好、自动信任,绿锁直接亮。不用 mkcert,不用 nginx,也不用改 hosts;WebSocket 会原样透传,Vite 的 HMR 热更新照样能用。

本地服务亮起绿锁,不用 hosts 不用 nginx

再进一步还能玩路径级路由(app.numa/api 转到 :5001),或者开 numa lan on,让局域网里几台机器通过 mDNS 自动发现彼此的服务——A 机器上的 api.numa,B 机器直接 curl 得到。

三、数据全在本地,查询还能加密

Numa 有三种解析模式,按需挑:

  • forward(默认):透明代理到你系统原来的 DNS,只叠加缓存和拦截。公司 VPN、酒店认证页、内网 DNS 全都不受影响,切换成本几乎为零
  • recursive:直接从根域名服务器递归解析,不依赖任何上游。配上 [dnssec] enabled = true 还能做完整信任链校验(RRSIG、DNSKEY、DS、NSEC/NSEC3 都覆盖)
  • auto:启动时探测根服务器,通就走递归,不通退回 DoH(Quad9)

加密这块也给得挺全:

  • DNS-over-TLS 监听(RFC 7858):iOS 的「加密 DNS」、systemd-resolved、stubby 这类严格客户端可以直接连 853 端口
  • ODoH(RFC 9230):查询用 HPKE 封给目标解析器,再经中继转发。中继只知道你的 IP、看不到问题;目标只知道问题、看不到你的 IP

DoT / ODoH,全程加密

三种装法,从轻到重

1. Docker 试水(本机什么都不装)

1
2
3
4
5
docker run -d --name numa -p 127.0.0.1:5553:53/udp -p 127.0.0.1:5553:53/tcp \
-p 127.0.0.1:5380:5380 ghcr.io/razvandimescu/numa

dig @127.0.0.1 -p 5553 example.com
docker exec numa numa token # 面板密码

打开 http://localhost:5380,用户名随便填,密码用上面 numa token 打印的那串。用 5553 是为了避开本机已经被占用的 53 端口。

2. 前台跑一下(不动系统 DNS)

1
2
3
4
5
6
7
8
9
10
11
12
13
# macOS
brew install razvandimescu/tap/numa

# Linux
curl -fsSL https://raw.githubusercontent.com/razvandimescu/numa/main/install.sh | sh

# Arch Linux
pacman -S numa

# 任意平台
cargo install numa

sudo numa # Ctrl-C 退出;占 53 端口需要 root/管理员

系统原本的 DNS 不会被改,用 dig @127.0.0.1 example.com 验证就行。Ubuntu / Mint 上 53 端口常被 systemd-resolved 占着,改一下 numa.toml 里的 bind_addr 或干脆用 Docker。

3. 设为系统 DNS(一条命令)

平台 安装 卸载
macOS sudo numa install sudo numa uninstall
Linux sudo numa install sudo numa uninstall
Windows numa install(管理员)+ 重启 numa uninstall(管理员)+ 重启

install 一次干三件事:注册系统服务、把系统 DNS 指过来、把本地 CA 加进系统信任库;uninstall 原样回滚。装好之后面板还能直接用 http://numa.numa 打开。

一个小坑:Linux 上 sudo 会走自己的 secure_path,跳过 ~/.cargo/bin,所以升级后要用全路径 sudo "$(command -v numa)" install。

手机也能接

1
numa setup-phone

终端里会打印一个二维码,iPhone / Android 扫一下、装描述文件、信任证书,手机的 DNS 就通过 DoT 走到 Numa 上了。前提是在 numa.toml 里打开 [mobile] enabled = true。

手机扫个码,DNS 就连上

性能和一些细节

  • 缓存命中 0.1ms,和 Unbound、AdGuard Home 同一水平
  • 请求对冲(request hedging):UDP / DoH / DoT 都支持,用并行请求压尾延迟,冷启动递归 p99 538ms,比 Unbound 的 748ms 低约 28%,波动也小得多
  • serve-stale + 预取(RFC 8767):上游挂了还能拿一小时内的旧缓存顶一下
  • 多上游按 SRTT 排优先级,自动故障转移
  • 支持按后缀条件转发,Tailscale、公司 VPN 的分流场景很好用
  • Hub 模式:一台机器设成 bind_addr = "0.0.0.0:53",其他设备 DNS 指过来,全屋都能享受拦截和 .numa 解析
  • 面板之外还有 REST API,覆盖 overrides、缓存、拦截、服务、诊断

它不做什么

  • 没有 DHCP,别指望它替代路由器
  • 不做多机集群、也不做实例间配置同步
  • 大部分设置写在 numa.toml 里,面板只覆盖常用项
  • 想给整个局域网当 DNS,还是得找台常开的机器

小结

Numa 最舒服的地方是把门槛压到几乎为零:不用树莓派、不用 Docker、不用云账号,一个 8MB 的二进制文件,装完就有广告拦截、本地域名绿锁和加密解析。经常出差、换网络频繁,又想在别人的 Wi-Fi 上清静一点的人,这个真的挺对味。

Numa 开源 MIT Rust

单文件便携 DNS 解析器:Hagezi Pro 广告拦截、.numa 本地域名自动 HTTPS、递归解析 + DNSSEC、DoT / ODoH 加密,一个约 8MB 的二进制跑遍 macOS、Linux、Windows,手机扫码即可接入。

★ 1578GitHub Star
⑂ 115Fork
MIT开源协议
单文件部署 广告拦截 本地域名 HTTPS DoT / ODoH