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.

Heimdall DNS: the Norse watchman guarding every query that crosses your edge, with domains travelling the Bifrost bridge.
~125 KBstatic binary
~1.6 MBidle RAM (RSS)
DNSSECserves signed NSEC3 zones
0private keys on the box

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.

Heimdall~1.6 MB
CoreDNS~40 MB
BIND9~70 MB

Idle RAM at rest, to scale. Heimdall is the thin teal sliver.

CapabilityHeimdall DNSCoreDNSPowerDNSBIND9
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 dependenciesNoneGo runtimeShared libs + backendShared libraries
LanguageC (musl)GoC++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 serverNone (kept in control plane)Depends on setupDepends on setupDepends on setup
ConfigOne fileCorefile + pluginsConfig + backend (often SQL)named.conf + zones
Containerscratch, non-rootLarger baseBase image + backendBase image
Plugin ecosystemIntentionally minimalLargeBackends + LuaLimited / 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.

A / AAAA MX TXT CNAME SRV CAA PTR TLSA SVCB / HTTPS SSHFP NAPTR DNAME RFC 3597 generic

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
DNS query arrives
Is it one of your zones?
yesAuthoritative answerserved instantly from your zone files
noRecurse from rootor forward to your upstream
One shared cacheserve-stale + prefetch, ACL-gated recursion

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.

Get Unicorn Panel Explore the stack

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.