Numa — DNS you own. Everywhere you go.
Description: DNS you own. Recursive resolver with full DNSSEC validation, ad blocking, .numa local domains, developer overrides. A single portable binary built from scratch in Rust.

# Numa

DNS you own. Everywhere you go.

After Numa Pompilius, who built institutions that outlasted kings.

Block ads and trackers. Override DNS for development. Name your local services with `.numa` domains. A single portable binary built from scratch in Rust — no Raspberry Pi, no cloud, no account.

Get Started Read the Architecture View on GitHub
The Problem

## DNS is a single point of control

Every time you visit a website, you ask a DNS resolver where to go. That resolver sees every domain you visit, when, and how often. Your ISP logs these queries by default.

Ad blockers work in one browser. Pi-hole needs a Raspberry Pi. Your local dev services live at `localhost:5173` and you can never remember which port is which.

DNS is the foundation of everything you do on the internet, but the tools for controlling it locally are either too complex (dnsmasq + nginx + mkcert) or too limited (cloud-only, appliance-only).

Your browser
Your ISP / OS resolver
|
Single point of failure
Cloudflare 1.1.1.1 / Google 8.8.8.8
|
ICANN root servers
TLD registrars (.com, .io, ...)
Authoritative nameservers
How It Works

## What it does today

A recursive DNS resolver with DNSSEC validation, ad blocking, local service domains, and a REST API. Everything runs in a single binary.

Layer 1

### Resolve & Protect

- Recursive resolution — resolve from root nameservers, no upstream needed
- DNSSEC validation — chain-of-trust + NSEC/NSEC3 denial proofs (RSA, ECDSA, Ed25519)
- Ad & tracker blocking — 385K+ domains, zero config
- DNS-over-HTTPS — encrypted upstream as alternative to recursive mode
- TTL-aware caching (sub-ms lookups)
- Single binary, portable — macOS, Linux, and Windows

Layer 2

### Developer Tools

- Local service proxy — `frontend.numa` instead of `localhost:5173`
- Path-based routing — `app.numa/api` → `:5001`
- Ephemeral DNS overrides with auto-revert
- LAN service discovery via mDNS
- Conditional forwarding — plays nice with Tailscale/VPN split-DNS
- REST API — script everything, automate anything
- Live dashboard with real-time stats and controls

Coming Next

### Self-Sovereign DNS

- pkarr integration — DNS via Mainline DHT, no registrar needed
- Global `.numa` names — self-publish, DHT-backed
- .onion bridge — human-readable names for Tor hidden services
- Ed25519 same-key binding — zero new trust assumptions
- No blockchain required for core naming

Architecture

## Resolution pipeline

Every query walks through the same deterministic pipeline. Local data takes priority; the network is the fallback.

Query
→
Overrides
→
.numa TLD
→
Blocklist
→
Local Zones
→
Cache
→
Recursive / Forward (DoH)
→
DNSSEC Validate
→
Respond
Comparison

## Why Numa is different

Comparison of Numa with existing DNS solutions
| Pi-hole | NextDNS | Cloudflare | AdGuard Home | Numa
--- | --- | --- | --- | --- | ---
Recursive resolver | No (needs Unbound) | Cloud only | Cloud only | No | Root hints + full DNSSEC
Ad & tracker blocking | Yes | Yes | Limited | Yes | 385K+ domains
Portable (travels with laptop) | No (Raspberry Pi) | Cloud only | Cloud only | No (network appliance) | Single binary
Developer overrides | No | No | No | No | REST API + auto-expiry
Local service proxy | No | No | No | No | .numa domains + WebSocket
Data stays local | Yes | Cloud | Cloud | Yes | 100% local
Live dashboard | Yes | Yes | No | Yes | Real-time + controls
DNS-over-HTTPS upstream | No | Yes | Yes | No | Built in (HTTP/2 + rustls)
Conditional forwarding | No | No | No | Manual | Auto-detects Tailscale/VPN
Zero config needed | Complex setup | Yes | Yes | Docker/setup | Works out of the box

Performance

## Measured, not claimed

Benchmarked with `dig` against public resolvers on the same machine. Cached queries resolve in under a microsecond.

DNS resolver latency comparison
Resolver | Avg | P50 | P99
--- | --- | --- | ---
Numa (cached) | <1ms | <1ms | <1ms
Numa (cold) | 9ms | 9ms | 18ms
System resolver | 9ms | 8ms | 44ms
Quad9 | 15ms | 13ms | 43ms
Cloudflare | 19ms | 14ms | 132ms
Google | 22ms | 17ms | 37ms

Numa
<1ms
System
9ms
Quad9
15ms
Cloudflare
19ms
Google
22ms
Under the Hood

## Technical details

Runtime
  Rust + tokio async (rt-multi-thread)
DNS Libraries
  Zero — wire protocol parsed from scratch
Resolution Modes
  Recursive (iterative from root hints, CNAME chasing, glue extraction) or Forward (DoH / plain UDP)
DNSSEC
  Chain-of-trust via ring — RSA/SHA-256, ECDSA P-256, Ed25519. NSEC/NSEC3 denial proofs. EDNS0 DO bit, 1232-byte payload (DNS Flag Day 2020).
Dependencies
  19 runtime crates — tokio, axum, hyper, ring (DNSSEC), reqwest (DoH), rcgen + rustls (TLS), socket2 (multicast), serde, and more
Packet Format
  RFC 1035 compliant. EDNS0 OPT pseudo-record. Parses A, AAAA, NS, CNAME, MX, SOA, SRV, HTTPS, DNSKEY, DS, RRSIG, NSEC, NSEC3.
Concurrency
  Arc<ServerCtx> + RwLock for reads, Mutex for writes (never across .await)

# Install (pick one) $ brew install razvandimescu/tap/numa $ cargo install numa $ curl -fsSL https://raw.githubusercontent.com/razvandimescu/numa/main/install.sh | sh # Run $ sudo numa # bind to :53, :80, :5380 $ dig @127.0.0.1 google.com # test resolution $ open http://localhost:5380 # dashboard $ curl -X POST localhost:5380/services \ -d '{"name":"frontend", "target_port":5173}' # https://frontend.numa
Roadmap

## Where we're going

Phase 0 DNS proxy core — zones, caching, forwarding, async tokio runtime
Phase 1 Override layer + REST API for programmatic DNS control
Phase 2 Ad & tracker blocking — 385K+ domains, live dashboard, one-click allowlist
Phase 3 System integration — auto-discovery of OS DNS routing, one-command install
Phase 4 Local service proxy — .numa domains, HTTP/HTTPS reverse proxy, auto TLS, WebSocket
Phase 5 DNS-over-HTTPS — encrypted upstream, HTTP/2 connection pooling
Phase 6 Recursive resolution — resolve from root nameservers, no upstream dependency
Phase 7 DNSSEC validation — chain-of-trust, NSEC/NSEC3 denial proofs, RSA + ECDSA + Ed25519
Phase 8 pkarr integration — self-sovereign DNS via Mainline DHT, no registrar needed
Phase 9 Global .numa names — self-publish, DHT-backed, first-come-first-served
Phase 10 .onion bridge — human-readable Tor naming via Ed25519 same-key binding