[server]

[server]
mode = "resolver"        # "resolver" | "authoritative" | "both"
user = "rdns"
group = "rdns"
pidfile = "/var/run/rdns/rdns.pid"

Mode is config-driven — same binary, different behavior. User/group are dropped to after binding port 53.

[listeners]

[listeners]
udp = ["0.0.0.0:53", "[::]:53"]
tcp = ["0.0.0.0:53", "[::]:53"]

[listeners.tls]
addresses = ["0.0.0.0:853", "[::]:853"]
cert = "/etc/rdns/tls/cert.pem"
key  = "/etc/rdns/tls/key.pem"

Each address in the list gets its own listener task. Use wildcard for HA (see Use cases).

[resolver]

[resolver]
forwarders = []                  # empty = full recursive from root hints
dnssec = true
qname_minimization = true
max_recursion_depth = 30

[authoritative]

[authoritative]
source = "none"                  # "zone-files" | "database" | "none"
directory = "/etc/rdns/zones"

[authoritative.database]
connection = "postgresql://rdns:password@localhost:5432/rdns"

PostgreSQL backend requires building with --features postgres.

[cache]

[cache]
max_entries = 1_000_000
max_ttl = 86400
min_ttl = 60
negative_ttl = 300
serve_stale = true
stale_max_ttl = 86400
stale_answer_ttl = 30

Serve-stale (RFC 8767) serves expired entries with a short TTL when upstream is down. Bounded by stale_max_ttl.

[rpz]

[[rpz.zones]]
name = "rpz.adblock"
file = "/etc/rdns/rpz/blocklist.rpz"

BIND-compatible RPZ files. Multiple zones allowed; first match wins.

[control]

[control]
socket = "/var/run/rdns/control.sock"

[metrics]

[metrics]
enabled = false
address = "127.0.0.1:9153"

Prometheus exposition format at /metrics.

[logging]

[logging]
level = "info"      # error | warn | info | debug | trace
format = "json"     # json | text

[security]

[security]
sandbox = true       # enable Capsicum on FreeBSD
rate_limit = 1000    # max QPS per source IP

[edns]

[edns]
udp_payload_size = 1232

Follows DNS Flag Day 2020. Values below 512 are clamped per RFC 6891.

The rdns-control CLI

rdns-control stats
rdns-control flush-cache
rdns-control flush-name example.com
rdns-control reload-zones

Metrics endpoint

Sample output at /metrics:

# HELP rdns_queries_total Total queries received
# TYPE rdns_queries_total counter
rdns_queries_total{listener="udp:0.0.0.0:53"} 1245678

# HELP rdns_cache_hits_total Cache hit count
# TYPE rdns_cache_hits_total counter
rdns_cache_hits_total 982341

# HELP rdns_query_duration_seconds Query handling latency
# TYPE rdns_query_duration_seconds histogram

The rdns.toml.example in the repo is the source of truth.

Get rDNS running in 60 seconds.

Single static binary. TOML config. MIT licensed. Linux, FreeBSD, and macOS.