DNS resolver
Stalwart resolves DNS names itself, with a built-in resolver, and every DNS lookup the server makes goes through it. When it delivers outgoing mail, the resolver finds the MX and address records of the recipient’s domain. When it checks incoming mail, it reads SPF, DKIM and DMARC records, and when it secures connections, MTA-STS and TLSA records. It also looks up the reverse DNS names of connecting clients, sends the DNSBL queries of the spam filter, and runs the propagation checks of automatic DNS management. The choice of name servers behind the resolver therefore affects much more than speed: it decides whether spam blocklists answer and whether DANE can be used at all.
The resolver sends its queries to the name servers selected on the DnsResolver singleton (found in the WebUI under Settings › Network › DNS › DNS Resolver).
Choosing the name servers
Section titled “Choosing the name servers”The variant of the DnsResolver decides where queries go:
Systemsends them to the name servers configured on the host, which on Unix systems are listed in/etc/resolv.conf.Cloudflare,Quad9andGooglesend them to the public resolvers of these operators. Cloudflare and Quad9 are queried over TLS unlessuseTlsis turned off.Customsends them to the name servers listed inservers. Each entry has anaddress, aportand aprotocol, which isudp,tcportls.
Two considerations decide the choice: DNSBL queries and DANE.
DNSBL queries
Section titled “DNSBL queries”A DNS blocklist (DNSBL) publishes the reputation of IP addresses and domains as DNS records, and the spam filter queries it for each message. Most blocklists refuse queries that arrive through large public resolvers, because the volume from those resolvers exceeds their free usage limits. Some answer such queries with a special code that means “query refused” instead. A server that uses Cloudflare, Google or Quad9 therefore loses most of its DNSBL checks.
To keep them, use a local caching resolver that queries the blocklists directly. It can be reached through System, provided that the host’s own resolver configuration does not forward to a public resolver, or configured as a Custom server.
DNSSEC and DANE
Section titled “DNSSEC and DANE”DANE lets a sending server authenticate the receiving server through TLSA records published in DNS. A TLSA record only has meaning when it has been validated with DNSSEC, because otherwise anyone able to forge DNS answers could also forge the record. Stalwart validates DNSSEC itself. For that, it needs a resolver that passes DNSSEC records through, and at least one name server reachable over TCP or TLS.
The server checks these conditions at startup. If the check fails, DANE verification of outgoing mail is turned off, and the server logs this warning:
The configured DNS resolver cannot validate DNSSEC. DANE has been disabled to avoid deferring mail. Ensure the resolver is DNSSEC-capable and reachable over TCP.The System variant connects to the host’s name servers over both UDP and TCP, so it meets the TCP condition on its own. A Custom resolver meets it only when at least one of its servers has protocol set to tcp or tls.
Recommended setup
Section titled “Recommended setup”A local validating resolver, such as Unbound running on the same host, satisfies both considerations. It queries the blocklists directly and validates DNSSEC, and it also caches answers for all the processes on the host.
Lookup settings
Section titled “Lookup settings”Every variant shares a set of settings that control how each lookup is carried out:
timeoutis the time to wait for an answer before the query is considered failed.attemptsis the number of times a failed query is retried.maxConcurrentRequestsis the number of name servers queried in parallel for each lookup, when several are configured. A value of 0 or 1 queries them one at a time.tcpOnErrorretries a query over TCP when it fails over UDP.enableEdnsturns on EDNS, the DNS extension that allows larger answers. DNSSEC needs it.preserveIntermediateskeeps the intermediate records of a CNAME chain in the result.
Caching
Section titled “Caching”Stalwart caches each answer for its TTL, in caches whose sizes are set on the Cache object. Negative answers, which state that a name or record does not exist, are cached as well, for at most Cache.negativeTtl. That limit is 1 hour unless changed. A record published after a failed lookup can therefore take that long to be seen by the server.
Example
Section titled “Example”The following resolver queries two local name servers. One of them is reached over TCP, so that DNSSEC validation, and with it DANE, remains available:
{ "@type": "Custom", "servers": { "0": {"address": "192.0.2.1", "port": 53, "protocol": "udp"}, "1": {"address": "192.0.2.3", "port": 53, "protocol": "tcp"} }, "maxConcurrentRequests": 1}