Reproducible, fully static, FROM-scratch DNS sinkhole benchmark harness, with one published real-world WAN result set.
Repository: github.com/ConYel/dns-sinkhole-bench
Published site: conyel.github.io/dns-sinkhole-bench
Five DNS sinkhole implementations, each built into a fully static binary inside a reproducible StageX container — no runtime dependencies, no package manager, no shell, no bullshit.
The published benchmark tests Pi-hole, Blocky, AdGuard Home, Ferrous DNS, and Numa DNS across 4 workload scenarios, 4 upstream providers, and 2 benchmark modes. The generated result site includes violin QPS plots and bar charts for latency, lost queries, and memory.
This repository is not claiming a universal DNS ranking.
It is:
- a reproducible container build setup;
- a reproducible benchmark harness;
- a published real-world WAN benchmark run;
- a static site generator for inspecting the raw result set.
It is not:
- a lab-isolated CPU microbenchmark;
- a same-host localhost benchmark;
- a long-duration stability test;
- a full security review;
- a tail-latency benchmark;
- a claim that your network will produce the same absolute numbers.
The topology is intentionally real-world:
client running dnsperf → public internet → VPS running sinkhole container → public internet → upstream resolver
That is where many people actually run this shitware1. It also means WAN routing, upstream resolver behavior, and transient internet conditions are part of the measured system.
- Only coarse geography is disclosed: EMEA client and EMEA VPS. Exact provider, IPs, regions, and timestamps are intentionally not published.
- Each server/provider/scenario/mode normally has 3 replicates. The merged CSV has 478 rows out of an expected 480; one common-denominator cell is incomplete and disclosed in
METHODOLOGY.mdandresults/schema.md. - Best-of-breed mode intentionally uses each server's native upstream transport: DoH for AdGuard Home, Blocky, and Ferrous; DoT for Numa; plain UDP DNS for Pi-hole FTL.
- Common-denominator mode forces plain UDP DNS upstream where possible, but Pi-hole is plain DNS in both modes because FTL v6 has no native DoH/DoT upstream support.
- Blocky relies on upstream DNSSEC validation by design.
- Ferrous DNS config-file blocking is not equivalent to the others; its blocked-mode result must be read with that caveat.
- dnsperf text output does not provide p50/p95/p99 latency, so latency is average latency only.
- Memory is a benchmark-time memory reading, not a full heap/RSS profile.
If you want stricter statistics, more replicates, randomized run order, repeated day/night runs, packet-loss baselines, or a different latency tool: please reproduce it and send a PR. The harness is here for exactly that. Or pay me to do it :P
| Image | Size | Language | Base |
|---|---|---|---|
| Pi-hole FTL v6.6.2 | 8.8 MB | C | StageX + source-built deps |
| Blocky v0.29.0 | 28.3 MB | Go | StageX pallet-go |
| Ferrous DNS v0.8.8 | 25.3 MB | Rust | StageX pallet-rust |
| AdGuard Home v0.107.77 | 24.5 MB | Go | StageX pallet-go (DNS only) |
| Numa DNS v0.21.0 | 10.1 MB | Rust | StageX pallet-rust |
- Static site:
docs/index.html - Main merged CSV:
bench/results/results.csv - Raw dnsperf output:
bench/results/*.txt - Result schema:
results/schema.md - Methodology:
METHODOLOGY.md - System disclosure template:
SYSTEM.md - Reproduction commands:
REPRODUCE.md - Server configs:
bench/configs/ - Workloads:
configs/workloads/ - Build definitions:
containers/ - Known issues and fixes:
FINDINGS.md,FIX_MANIFEST.md
make bench-buildVerify reproducible container builds:
make verify-allcp vps-config.example.sh vps-config.sh
$EDITOR vps-config.sh
./scripts/run-benchmark-modes.sh both vps-config.shChoose a single mode if needed:
./scripts/run-benchmark-modes.sh best vps-config.sh
./scripts/run-benchmark-modes.sh plain vps-config.sh
./scripts/run-benchmark-modes.sh mergeGenerate the static result site from the current merged CSV:
make bench-sitemake bench-test # smoke-test dnsperf output parsing
make bench-lint # shellcheck all scriptsmake bench-lint requires ShellCheck.
This repo is already laid out for GitHub Pages from docs/:
- Push the repository to GitHub.
- Repository Settings → Pages.
- Source: deploy from a branch.
- Branch:
master. - Folder:
/docs.
The public URL will be:
https://conyel.github.io/dns-sinkhole-bench/
Why not disclose the VPS provider? Because exact infrastructure identity is not needed to reproduce the harness and creates avoidable privacy/abuse surface. Coarse EMEA geography and system specs are enough context for interpreting the published run.
Why not run for days? Because this benchmark intentionally avoids hammering public DNS resolvers for long periods. If you need longitudinal measurements, run them responsibly on your own infrastructure and document the policy.
Why only 3 replicates? Because the full matrix is already large: 5 servers × 4 providers × 4 scenarios × 2 modes × 3 replicates. More replicates are welcome, but the current dataset is disclosed honestly rather than over-claimed.
Why WAN instead of localhost? Because the goal is real-world deployment behavior, not only pure server-loop throughput.
Why include best-of-breed if transports differ? Because deployments differ. The common-denominator mode exists to reduce this confound; the best-of-breed mode shows what the software actually does when configured naturally.
This benchmark was made in France. For anyone who thinks it is not a real country, or that it is third world:
"Ceci n'est pas une pipe" %>% gsub("une", "un", .)you know where to put it.
⬢ Reproducible build foundation — This project stands on other people's work. I am grateful to the StageX maintainers for the reproducible build toolchain and pallet images that made the static scratch-container builds practical: 🛡️ Lance R. Vick, 🪙 Anton Livaja, 🔑 Ryan Heywood, 🌐 Danny Grove, 👛 Matthew Brooks, 💻 Jakub Panek, and 🧩 Zoë Finja Emilia Kron.
◈ DNS projects under test — Respect to the maintainers of the DNS projects benchmarked here. This benchmark exists because their projects exist: Pi-hole FTL, Blocky, AdGuard Home, Ferrous DNS, and Numa DNS.
✦ Benchmark and publishing stack — Appreciation also goes to the maintainers of the tools used to run and publish the benchmark: DNS-OARC dnsperf, BIND/dig, Podman, ShellCheck, GNU Make, Python, Bash, Chart.js, and chartjs-chart-boxplot.
◆ Workflow companions — Finally, thanks to ZeroClaw and opencode for helping drive the coding workflow, and to ThePrimeagen (GitHub), whose videos were running in the background while this project was built.
Repository-owned code, scripts, configuration templates, documentation, and build harness files are licensed under AGPL-3.0-or-later, or under a separate commercial license for users who do not want AGPL terms; see LICENSE and LICENSE-COMMERCIAL.
Benchmark data and generated reports are licensed under Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0); see results/LICENSE. Attribution is required, and commercial/product use is not allowed without separate written permission.
Third-party software remains under its own upstream licenses; see THIRD_PARTY_LICENSES.md.
Footnotes
-
"Yeah, well, you know, that's just, like, your opinion, man." Also: "Everything is a copy of a copy of a copy." More plainly: humans write software, humans make mistakes, and every non-trivial system is broken somewhere. ↩
