sdns is a free, open source networking & connectivity project written in Go and released under MIT. It has 1,086 GitHub stars, 72 forks and 0 open issues, and was last pushed 10 hours ago. On this registry it ranks #41 of 43 tracked projects in Networking & Connectivity, with 5 head-to-head comparisons available.

What is sdns?

sdns is a high-performance recursive DNS resolver written in Go that resolves from the root, validates answers against DNSSEC trust anchors and serves DNS over UDP, TCP, TLS, HTTPS and QUIC, intended for operators and privacy-focused self-hosters who want to run their own resolving name server instead of relying on a third-party resolver.

What it is

sdns is a recursive DNS resolver server, written in Go and released under the MIT licence. It resolves queries from the root of the DNS rather than forwarding them to an upstream provider, validates the answers it receives against the DNSSEC trust anchors, and caches the results. It sits in the networking and connectivity corner of infrastructure operations, serving the protocols clients actually speak today: plain UDP and TCP, DNS over TLS (RFC 7858), DNS over HTTPS with HTTP/3 (RFC 8484) and DNS over QUIC (RFC 9250). Warm, wire-eligible cache hits are answered from the bytes the server already holds, served allocation-free, with batched recvmmsg/sendmmsg on Linux.

The concrete problem it replaces is a dependency on someone else's resolver. A network that points its clients at a public DNS service hands that service a record of every name looked up. sdns puts the recursion, the DNSSEC validation and the cache back on hardware the operator controls, so queries leave the network only as resolution traffic from the root down. It also solves the operational problem of running such a resolver safely, providing a recursion firewall that bounds the work a single request may cause, serving bounds derived from the machine at startup, and a validation gate that reports every configuration problem at once instead of one per restart.

Key capabilities

  • Recursive resolution from the root with DNSSEC validation, QNAME minimisation (RFC 9156), aggressive NSEC use (RFC 8198), NXDOMAIN subtree cuts (RFC 8020), failure caching (RFC 9520) and Extended DNS Errors (RFC 8914).
  • Optional root zone served from a ZONEMD-verified local copy (RFC 8806), and expired answers served as a last resort when resolution fails (RFC 8767).
  • Transports covering UDP, TCP, DoT (RFC 7858), DoH with HTTP/3 (RFC 8484) and DoQ (RFC 9250).
  • Policy enforcement through Response Policy Zones with name, client-address and answer-address triggers, fed from files or TSIG-signed AXFR, plus a shadow mode whose counters predict what enforcement would do.
  • Blocklists, per-client views, access lists, rate limits and reflection-attack detection.
  • Support for other namespaces: per-zone conditional forwarding, whole-server forwarder mode, Kubernetes cluster DNS, DNS64 synthesis (RFC 6147), EDNS Client Subnet (RFC 7871) and locally served zones (RFC 6303).
  • Operations tooling including Prometheus metrics, an HTTP API and dnstap.

Who uses it and how

  • Self-hosters on Linux, macOS, Windows or the BSDs, installing through pre-built binaries, .deb and .rpm packages, Homebrew, Snap or the Arch user repository.
  • Container-based deployments that mount a config with -c /etc/sdns.conf and persist state to a /var/lib/sdns volume, with images published to ghcr.io/semihalev/sdns and c1982/sdns.
  • Operators running Kubernetes cluster DNS, or a whole-server forwarder in front of existing infrastructure.
  • Networks needing per-client views and policy zones, where a shadow-mode pass is used to measure what enforcement would block before it is enabled.
  • Production deployments that pin a release tag rather than following latest.

Getting started

The quickest path is go install github.com/semihalev/sdns@latest; package and container options include brew install semihalev/tap/sdns, snap install sdns, yay -S sdns-git, and docker run against ghcr.io/semihalev/sdns:latest. Starting without a config writes one, documented in place, and uses it; sdns -t -c /etc/sdns.conf checks a config the way the server will read it, and dig @127.0.0.1 example.com A +dnssec returns an answer carrying the ad flag when it was validated.

How it compares

No comparable resolvers are named in the facts provided for this entry, so sdns stands alone in this registry on that basis.

When to use it — and when not

A self-hoster takes on a configuration file, a state directory or volume, and the operational duty of keeping the resolver patched and its metrics watched; the first query is slow while the root and trust anchor are primed, which is expected rather than a fault. Operators who want a fully managed resolution service, or who cannot own a persistent volume and a config lifecycle, should not pick it. The README itself is deliberately narrow, covering installation and a first answer rather than the full feature set, and the accesslist allows every client by default, so the documentation at sdns.dev should be read before exposing the server beyond loopback.

project readme (upstream, from github) — read inline

SDNS

A recursive DNS resolver with DNSSEC validation, written in Go.

Documentation · Install · Configuration · Benchmarks


SDNS resolves from the root, validates answers against the DNSSEC trust anchors, and caches them. It serves DNS over TLS, HTTPS and QUIC alongside plain UDP and TCP, and answers warm cache hits from the bytes it already holds.

Full documentation lives at sdns.dev. This file covers installing it and getting a first answer out of it.

Install

go install github.com/semihalev/sdns@latest

Pre-built binaries for Linux, macOS, Windows and the BSDs, plus .deb and .rpm packages, are on the releases page. The full architecture matrix is in the installation guide.

# Docker. Loopback because the default access list allows every client; -c and
# directory = "/var/lib/sdns" in the file because the image has no WORKDIR, so
# a relative state directory resolves to /db and misses the volume entirely.
docker run -d --name sdns \
  -p 127.0.0.1:53:53 -p 127.0.0.1:53:53/udp \
  -v sdns-data:/var/lib/sdns -v "$PWD/sdns.conf:/etc/sdns.conf:ro" \
  ghcr.io/semihalev/sdns:latest -c /etc/sdns.conf

# macOS
brew install semihalev/tap/sdns && brew services start sdns

# Linux
snap install sdns

# Arch
yay -S sdns-git

Images are published to ghcr.io/semihalev/sdns and c1982/sdns on every tagged release. Pin a tag in production rather than following latest, the installation page names the current one, since this file cannot.

Quick start

# Starting without a config writes one, documented in place, and uses it.
sdns

# Check a config the way the server will read it, before restarting.
sdns -t -c /etc/sdns.conf

# Ask it something.
dig @127.0.0.1 example.com A +dnssec

An answer with the ad flag was validated. The first query is slow while the resolver primes the root and fetches the trust anchor; after that it is served from cache.

See Your first configuration for the handful of settings worth changing straight away, in particular accesslist, which allows everyone by default.

What it does

Resolution. Recursive from the root with DNSSEC validation, QNAME minimisation (RFC 9156), aggressive NSEC use (RFC 8198), NXDOMAIN subtree cuts (RFC 8020), failure caching (RFC 9520), and Extended DNS Errors (RFC 8914). Optionally the root zone served from a ZONEMD-verified local copy (RFC 8806), or expired answers as a last resort when resolution fails (RFC 8767).

Transports. UDP, TCP, DoT (RFC 7858), DoH with HTTP/3 (RFC 8484), DoQ (RFC 9250). Warm wire-eligible cache hits are served allocation-free, with batched recvmmsg/sendmmsg on Linux.

Policy. Response Policy Zones with name, client-address and answer-address triggers, file and TSIG-signed AXFR feeds, and a shadow mode whose counters predict what enforcement would do. Blocklists, per-client views, access lists, rate limits, and reflection-attack detection.

Other namespaces. Per-zone conditional forwarding, whole-server forwarder mode, Kubernetes cluster DNS, DNS64 synthesis (RFC 6147), EDNS Client Subnet (RFC 7871), locally served zones (RFC 6303).

Operations. Prometheus metrics, an HTTP API, dnstap, a recursion firewall that bounds the work one request may cause, serving bounds derived from the machine at startup, and a validation gate that reports every configuration problem at once.

The documentation covers each of these, including what they cost and what they deliberately do not do.

Performance

Throughput measurements, the methodology, resolver comparisons and their caveats are in the benchmarks document.

Development

make all     # generate, tidy, test, build
make test    # tests only
go build     # binary only

Conventions a patch is expected to follow (plain testing idioms with no assertion library, no live-network tests, gofmt and golangci-lint clean) are on the building and testing page. The middleware interface and the plugin contract are documented there too.

Contributing

Pull requests are welcome. For significant changes, please open an issue first so the approach can be discussed.

Please review CONTRIBUTING.md before submitting patches.

Made with

Inspired by

License

MIT

Frequently asked questions

Is sdns free to use?

sdns is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does sdns do?

A high-performance, recursive DNS resolver server with DNSSEC support, focused on preserving privacy.

What is sdns written in?

sdns is primarily written in Go. Its source is publicly available at https://github.com/semihalev/sdns, and it has 1,086 GitHub stars.