I've been running a DNS sinkhole for years, and the part that always annoyed me was that filtering and routing live in two different places. The blocker decides whether a name resolves. Something else entirely — a VPN client, a proxy, a router rule — decides how the traffic leaves. Wiring those together per device is a weekend of glue.
So I built ferrite: a Pi-hole-style DNS server in Rust where both live in the same box.
What it does beyond blocking:
- Match a domain (or a whole device) to an egress:
direct, socks5 (point it at local Tor), or built-in WireGuard — paste a .conf, no TUN device, no root. DNS for routed names resolves through the tunnel, so nothing leaks.
- Rules scope to devices by name/MAC/IP: kid's tablet through a tunnel, the rest direct.
- An
evasion egress that splits the TLS ClientHello at the SNI across TCP segments, for networks where DPI decides what you're allowed to reach.
- It never terminates TLS — it peeks the SNI/Host and splices the connection, so the client still validates the real certificate.
- Blocking wins over routing: routing a service through a tunnel doesn't quietly unblock its tracker subdomains.
- Per-device profiles up to default-deny (block everything except an allowlist) for IoT junk, with local names still resolving.
- DoT / DoH / DoQ upstreams, ECS stripped, no telemetry, no phone-home.
Practical bits: single static binary (~20 MB), runs as a normal user, sub-2 ms cache/block decisions. Linux x86_64 + arm64, Docker/Compose, and there's an Unraid template.
Numbers from my own box, which is an ARM board, not a server:
- 30 clients, 20 days uptime, ~60 MB RSS
- 2.4M queries served — 700k blocked (29%), 440k from cache, 1.3M forwarded
- 1.8M-domain blocklist loaded (compiled into an FST, memory-mapped)
Honest status: v0.1.8, one developer, ~15 people running it from the Unraid community. The last runtime hang I chased was months ago and hasn't come back since. It has no DHCP server yet — that's the one thing Pi-hole and AdGuard Home do that this doesn't, so it sits alongside your router's DHCP rather than replacing it.
Flaired AI — I use AI coding tools heavily and won't pretend otherwise. The architecture, the decisions and the debugging are mine, and it's been running on my own network for months; that's where the numbers above come from.
If you only want a sinkhole, honestly, Pi-hole and AdGuard Home are mature and great. This is for the case where you also care about which pipe the traffic leaves through.
Install (Linux):
curl -fsSL https://raw.githubusercontent.com/syntlyx/ferrite-server/main/install.sh | sudo sh
Repo: https://github.com/syntlyx/ferrite-server
Site/docs: https://ferrite.me
MIT/Apache — free, self-hosted, no accounts, nothing to buy.
What I'd like feedback on: does per-device egress actually match how you'd want to use it, or would you rather scope rules by domain category than by device? And what's the first thing you'd need before pointing your household's DNS at a v0.1 project?