Heimdall DNS
DNS that disappears
into ~1.6 MB of RAM
Heimdall is a single ~125 KB static binary that serves your DNSSEC-signed zones and is both an authoritative nameserver and a full from-root recursive resolver. No private keys on the box, no Go runtime, no 45 MB image. One config file, and a process you can actually read.

Measured on Alpine: ~125 KB static binary, 216 KB scratch image, 1.56 MB RSS at rest. DNSSEC serving validated secure by unbound-host.
Spamhaus refuses public resolvers like 1.1.1.1 and 8.8.8.8. Heimdall recurses from your own IP, so your mail server's DNSBL lookups actually resolve.
The resolver your mail server has been asking for
Blocklists refuse public resolvers. You need your own.
DNS blocklists like Spamhaus refuse queries from public resolvers such as 1.1.1.1 and 8.8.8.8. A mail server has to resolve them through a recursive resolver that queries from its own IP. Most lightweight DNS tools only forward to an upstream, so they cannot do this. Heimdall runs a full from-root recursive resolver in the same tiny binary. That is the difference between blocklist lookups that work and a stack of CoreDNS plus Unbound.
- Full from-root recursion from your own IP
- Works with Spamhaus and other DNSBLs
- Authoritative for your zones in the same process
# public resolvers get refused by Spamhaus $ dig @1.1.1.1 2.0.0.127.zen.spamhaus.org ;; status: REFUSED # Heimdall recurses from your own IP, so it answers $ dig @localhost 2.0.0.127.zen.spamhaus.org 127.0.0.2 ; listed
By the numbers
Featherweight, on purpose
Heimdall is lean by design and ready for production, and it stayed tiny even after gaining DNSSEC serving, DNS Cookies, QNAME minimization, and a pile of new record types. The binary size and idle RAM below are measured; numbers marked with a tilde are approximate.
Idle RAM at rest, to scale. Heimdall is the thin teal sliver.
| Capability | Heimdall DNS | CoreDNS | PowerDNS | BIND9 |
|---|---|---|---|---|
| Binary size | ~125 KB | ~45 MB binary | ~MBs binary + libs | ~MBs binary + libs |
| RAM at rest | ~1.6 MB | ~40 MB | ~tens of MB | ~70 MB+ |
| Runtime dependencies | None | Go runtime | Shared libs + backend | Shared libraries |
| Language | C (musl) | Go | C++ | C |
| Authoritative + from-root recursion in one process | ● | Second service (Unbound/BIND) | Separate daemons | ● |
| Serve DNSSEC-signed zones (NSEC3, wildcards) | ● validated | ● (plugin) | ● | ● |
| Private keys on the DNS server | None (kept in control plane) | Depends on setup | Depends on setup | Depends on setup |
| Config | One file | Corefile + plugins | Config + backend (often SQL) | named.conf + zones |
| Container | scratch, non-root | Larger base | Base image + backend | Base image |
| Plugin ecosystem | Intentionally minimal | Large | Backends + Lua | Limited / views |
Heimdall's binary size and idle RAM are measured: a ~125 KB static binary (216 KB scratch image) using about 1.56 MB RSS at rest, even after adding DNSSEC serving, DNS Cookies, QNAME minimization, and the new record types. DNSSEC serving is validated secure by unbound-host against a real ECDSAP256SHA256 NSEC3 zone. Other figures are approximate and depend on version and build. CoreDNS, PowerDNS, and BIND are all mature, capable projects: the difference is fit and footprint.
DNSSEC, served not signed
Serve signed zones, hold no keys
Sign your zones however you like, with ldns-signzone or your control plane, then drop the signed file in and Heimdall serves it. It auto-detects a signed zone, returns RRSIGs when the query sets the DO bit, and generates correct NSEC3 denial-of-existence proofs for NXDOMAIN and NODATA, including wildcards. To be precise: Heimdall serves signed zones. It does not sign them, and it does not validate the answers it resolves. There are no private keys and no signing crypto in the server, so your public-facing DNS edge holds no secrets.
- Serves pre-signed NSEC3 zones, RRSIGs on the DO bit
- Correct NSEC3 denial-of-existence, including wildcards
- Validated secure end-to-end by unbound-host
- No private keys on the box; signing stays in your control plane
# sign in your control plane, drop the file in, Heimdall serves it $ ldns-signzone -n example.com.zone Kexample.com.+013... $ dig +dnssec @localhost example.com A | grep RRSIG example.com. 3600 IN RRSIG A 13 2 3600 ... # an independent validator agrees $ unbound-host -D example.com example.com has address 203.0.113.10 (secure)
Authoritative + recursive, one binary
Two servers in one process
Every record type a modern zone needs, from the everyday to DANE and the RFC 9460 service records, plus a generic escape hatch for anything else.
BIND-style zones
Master zone files with SOA, NS, A, AAAA, CNAME, MX, TXT, PTR, SRV, and CAA records. Correct NXDOMAIN and NODATA with SOA.
ALIAS / ANAME
Flatten a CNAME onto a zone apex: point the apex at a CDN hostname and still serve SOA, NS, and MX. A plain CNAME cannot do that.
Wildcards
Wildcard records (*.example.com) with RFC 4592 closest-encloser, correct under DNSSEC, plus CNAME chasing and minimal responses.
From-root recursion
Full iterative resolution from the root using your own IP, or forward mode to /etc/resolv.conf.
Smart resolution
Delegation and nameserver-IP caching skip the root on repeat lookups. Two-server racing plus one retransmit shrugs off a slow server or a dropped packet.
Per-record fault tolerance
One malformed record is logged and skipped while the rest of the zone still loads, and a broken zone never stops the server from starting.
Caching, hardening, observability
Honest and ops-friendly
Serve-stale + prefetch
Honors TTLs with min/max clamps and negative caching. RFC 8767 serve-stale keeps answering while it refreshes, and prefetch warms popular entries so there is never a cold miss.
Hardened by default
Recursion ACL (CIDR allow-list), so never an open resolver. RFC 8482 minimal-ANY neuters the cheapest amplification trick, with response rate limiting for untrusted clients.
DNS Cookies
RFC 7873 and 9018 DNS Cookies add anti-spoofing and anti-amplification per transaction, so they keep working even behind NAT where per-IP defences do not.
QNAME minimization
RFC 9156 on the recursive path: Heimdall sends only the minimal label to each server, so root and TLD operators never see your full query names.
Per-domain metrics
A rolling 7-day JSON file of per-domain query counts (for example, how many Spamhaus lookups this week), plus live CHAOS stats: version.bind, hostname.bind, stats.heimdall.
Protocols
IPv4 and IPv6, UDP and TCP, EDNS0, with automatic truncation and TCP fallback.
Zero-downtime reload
Reload with SIGHUP or udns -r. Test before you ship with -t config test and --test-zones validation.
Tested, small enough to audit
A few thousand lines of readable C, clean under AddressSanitizer and UBSan, with an automated suite of unit and integration tests that runs green in CI. Small enough that you could read it yourself.
How it works
One process, two jobs, one cache
Queries for your own zones short-circuit and answer instantly. Everything else recurses from the root, or forwards to your upstream if you prefer. Both paths feed one shared cache with serve-stale and prefetch, and recursion is gated by your ACL so it is never open to the world.
- Authoritative answers for your zones, instantly
- From-root recursion (or forward) for everything else
- One shared cache, with serve-stale and prefetch
- Live introspection over CHAOS queries
See the config
The whole thing is one small file
No messy config files. This is a complete, working configuration, and inside Unicorn Panel it is written and reloaded for you.
# dns.conf · the entire config file listen 0.0.0.0 listen :: zones-dir /opt/upcp/services/upcp-udns/zones recursion on allow-recursion 10.0.0.0/8
How to get it
Heimdall ships with Unicorn Panel
Heimdall DNS is exclusive to Unicorn Panel. Enable the DNS role and the panel installs it, writes the config, manages your zones from the UI, and keeps it updated. There is nothing separate to download or babysit.
Questions
Straight answers
Does Heimdall do DNSSEC?
It serves DNSSEC-signed zones. Sign your zone in your control plane (for example with ldns-signzone), drop the signed file in, and Heimdall serves it: it returns RRSIGs when the query sets the DO bit and generates correct NSEC3 denial-of-existence proofs, including for wildcards. This is validated secure by independent resolvers such as unbound-host. Heimdall does not sign zones, and it does not validate the answers it resolves recursively.
Where do the keys live?
Not on the DNS server. Signing and private keys stay in your control plane or signer; Heimdall holds no private keys and no signing crypto, so your public-facing DNS edge carries no secrets.
DANE / TLSA for mail?
Yes. Heimdall serves TLSA records for DANE, alongside the other modern types like SVCB, HTTPS, SSHFP, NAPTR, DNAME, and RFC 3597 generic records.
Is it production-ready?
Yes. It runs real mail and edge workloads in production, is memory-safe-tested (AddressSanitizer / UBSan clean), and ships with an automated suite of unit and integration tests that runs in CI.
Can it replace CoreDNS?
Yes, for authoritative and recursive DNS it is a drop-in replacement, and it serves DNSSEC-signed zones. It does not do recursive DNSSEC validation, and a sprawling plugin ecosystem is intentionally not the goal.
How do I migrate from CoreDNS?
Point it at a directory of BIND-style zone files, flip recursion on, and set your allow-recursion ACL. See the docs for the details.
Encrypted DNS (DoH / DoT)?
Not today. Heimdall speaks plain DNS over UDP and TCP with EDNS0.
Switch to something you can hold in your hand.
A ~125 KB binary that serves your DNSSEC-signed zones and holds no keys. Authoritative and recursive in one, ~1.6 MB of RAM, one config file, zero dependencies.