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

This project is maintained by semihalev

SDNS :rocket:

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


Use the go get command to install sdns:

go get

Pre-build Binaries

You can download the latest release from the Github Repo.


$ docker run -d --name sdns -p 53:53 -p 53:53/udp sdns

Docker Compose

Install docker-compose and run from the root directory:

$ sudo apt install docker-compose
$ docker-compose up -d

Homebrew for macOS

Install and run as a service:

$ brew install sdns
$ brew install semihalev/tap/sdns (updated every release)
$ brew services start sdns


$ snap install sdns

AUR for ArchLinux

$ yay -S sdns-git

Note: Pre-built binaries, Docker packages, brew taps, and snaps are automatically created by Github workflows.

Building from Source

$ go build


$ make test


Flag Desc
-c, –config PATH Location of the config file. If it doesn’t exist, a new one will be generated.
-v, –version Show the version of the sdns.
-h, –help Show this help and exit.

Debugging Environment

To debug your environment, execute the following command:

$ export SDNS_DEBUGNS=true && export SDNS_PPROF=true && ./sdns

The SDNS_DEBUGNS environment variable is beneficial for verifying the RTT (Round Trip Time) of authoritative servers. To use it, send an HINFO query for zones with chaos class.

Here’s an example of the output you might receive:

$ dig chaos hinfo

; <<>> DiG 9.17.1 <<>> chaos hinfo
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29636
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1

; EDNS: version: 0, flags:; udp: 1232
; COOKIE: f27dbb995df5ac79e4fa37c07d131b5bd03aa1c5f802047a7c02fb228a886cb281ecc319323dea81 (good)

;; AUTHORITY SECTION:		0	CH	HINFO	"Host" "IPv4: rtt:142ms health:[GOOD]"		0	CH	HINFO	"Host" "IPv4: rtt:145ms health:[GOOD]"		0	CH	HINFO	"Host" "IPv6:[2001:500:8f::53]:53 rtt:147ms health:[GOOD]"		0	CH	HINFO	"Host" "IPv6:[2001:500:8d::53]:53 rtt:148ms health:[GOOD]"

Configuration (v1.3.3)

Key Description
version Configuration version
directory sdns working directory (must grant write access to sdns user)
bind DNS server binding address Default: :53
bindtls DNS-over-TLS server binding address Default: :853
binddoh DNS-over-HTTPS server binding address Default: :8053
binddoq DNS-over-QUIC server binding address Default: :853
tlscertificate Path to the TLS certificate file
tlsprivatekey Path to the TLS private key file
outboundips Outbound IPv4 addresses (randomly chosen if multiple entries provided)
outboundip6s Outbound IPv6 addresses (randomly chosen if multiple entries provided)
rootservers DNS Root IPv4 servers
root6servers DNS Root IPv6 servers
rootkeys Trusted DNSSEC anchors
fallbackservers Failover resolver IPv4 or IPv6 addresses with port (leave blank to disable) Example: “”
forwarderservers Forwarder resolver IPv4 or IPv6 addresses with port (leave blank to disable) Example: “”
api HTTP API server binding address (leave blank to disable)
blocklists Remote blocklist address list (downloaded to the blocklist folder)
blocklistdir [DEPRECATED] Directory creation is automated in the working directory
loglevel Log verbosity level (crit, error, warn, info, debug)
accesslog Location of the access log file (leave blank to disable) Default: Common Log Format
nullroute IPv4 address for forwarding blocked queries
nullroutev6 IPv6 address for forwarding blocked queries
accesslist Client whitelist for query permissions
querytimeout Maximum wait duration for DNS query response Default: 10s
timeout Network timeout duration for each DNS lookup Default: 2s
hostsfile Enable serving zone data from a hosts file (leave blank to disable)
expire Default error cache TTL (in seconds) Default: 600
cachesize Cache size (total records in cache) Default: 256000
prefetch Cache prefetch before expiry (threshold: 10%-90%, 0 to disable)
maxdepth Maximum iteration depth per query Default: 30
ratelimit Query-based rate limit per second (0 to disable) Default: 0
clientratelimit Client IP address-based rate limit per minute (no limit if client supports EDNS cookie) Default: 0
blocklist Manual blocklist entries
whitelist Manual whitelist entries
cookiesecret DNS cookie secret (RFC 7873) - auto-generated if not set
nsid DNS server identifier (RFC 5001) - useful for operating multiple sdns instances (leave blank to disable)
chaos Enable responses to version.server, version.bind, hostname.bind and id.server chaos txt queries
qname_min_level Qname minimize level (0 to disable - higher values increase complexity and impact response performance)
emptyzones Enable response to RFC 1918 zone queries. For details, see

Plugin Configuration

In sdns, you have the ability to add custom plugins. The sequence of the plugins and the middlewares has a mutual impact on their execution. Config keys must be strings, and values can be of any type. Plugins are loaded before the cache middleware in the specified order.

The plugin interface is straightforward. For additional information, please refer to the example plugin.

Example Configuration

     path = "/path/to/"
     config = {key_1 = "value_1", intkey = 2, boolkey = true, keyN = "nnn"}
     path = "/path/to/"

Server Configuration Checklist




Benchmark Environment

Benchmarking Tool

Benchmark Comparisons

Benchmarks were performed on the following DNS resolvers: sdns-1.3.3, pdns-recursor-4.8.4, bind-9.19.12, unbound-1.17.1.

Benchmark Results

SDNS 100% 1 35,164 866 13,969 87s47ms 571/s
PowerDNS 99.99% 6 35,140 893 13,961 88s83ms 563/s
Bind 99.74% 132 35,024 885 13,959 127s64ms 390/s
Unbound 99.49% 253 35,152 624 13,971 174s64ms 284/s


We welcome pull requests. If you’re considering significant changes, please start a discussion by opening an issue first.

Before submitting patches, please review our CONTRIBUTING guidelines.

:hearts: Made With

Inspired by