How rtpdns works

rtpdns is built from two widely used open-source DNS servers, wired together so that a change made in one place reaches every nameserver within seconds. Here's how the pieces fit, what we learned building it, and what it costs to run.

Two kinds of server

A hidden primary holds every zone. It's PowerDNS Authoritative with a Postgres database: it signs zones with DNSSEC, takes changes through its API, and copies in customers' zones for secondary DNS. It's hidden because no NS record points at it, so resolvers never query it.

Public nameservers answer every query. They run Knot DNS, developed by CZ.NIC, the registry for .cz domains. They have no configuration of their own for customer zones: they copy everything from the primary.

customer's DNS server     (secondary DNS only)
        │  zone transfer
        ▼
hidden primary            PowerDNS + Postgres, signs zones
        │  NOTIFY + zone transfers, signed with TSIG
        ├────────────► ns1.rtpdns.com   Knot DNS
        └────────────► ns2.rtpdns.com   Knot DNS
                              ▲
                              │  queries
                     resolvers on the internet

Zones appear everywhere on their own

Adding every new zone to every nameserver's configuration is the classic chore of running DNS. Instead, the primary publishes a catalog zone (RFC 9432): a special zone whose records list all the other zones. Each nameserver transfers the catalog and serves whatever it lists. Create a zone on the primary and it joins the catalog. The primary sends a NOTIFY, and within seconds every nameserver has transferred the new zone and is answering for it. Delete a zone, and it disappears everywhere the same way.

Two things tripped us up:

Keys that can't collide, zones that can't hijack

Every zone transfer is signed with TSIG. The nameservers share one key with the primary. Secondary DNS customers bring their own, and because PowerDNS keeps all keys in one list, a customer's key must be named under their own zone, like xfr.example.com. Two customers can never pick the same name, so nobody can replace someone else's key.

The tool that creates zones also refuses any zone that could take over someone else's names: top-level domains, our own domain, and zones inside or above an existing zone. Every nameserver serves every zone and answers from the most specific one, so a stranger's www.example.com zone would otherwise hijack example.com's website.

A primary that only listens for NOTIFY

For secondary DNS, customers' servers have to reach the primary: they send it a NOTIFY when a zone changes, and allow it to transfer the zone. So the primary has its own public address, xfr.rtpdns.com. But PowerDNS has no response rate limiting, and an authoritative server that answers anyone can be used to amplify attacks on third parties. So from the internet, the firewall lets through exactly one kind of packet: a DNS NOTIFY over UDP. It reads the opcode straight out of the DNS header with the u32 match in iptables:

iptables -A rtpdns-notify-only -p udp \
    -m u32 --u32 "0>>22&0x3C@8>>11&0xF=4" -j RETURN

Everything else from outside is dropped. The primary's own SOA checks and zone transfers leave from the same address, so customers only have to allow one IP.

DNSSEC

Managed zones are signed with ECDSA P-256 (algorithm 13) and NSEC3. Only the primary holds signing keys; the nameservers serve the signed zones as they receive them. Signatures are valid for three weeks and refreshed weekly, so signed zones would keep validating for at least a week even if the primary went down.

Counting queries

Pricing depends on zones and queries, so every nameserver counts queries per zone with Knot's statistics module. Response rate limiting (RRL) handles floods: in our lab, a burst of 1,000 identical queries from one address got about 120 full answers, a similar number of truncated answers telling the client to retry over TCP, and the rest were dropped. The counts include rate-limited queries, so attack traffic has to be filtered out before it reaches an invoice.

Nameservers anywhere

A nameserver at another provider doesn't need access to our private network. It connects out to the primary's server over WireGuard and reaches the primary through the tunnel, so it can sit behind NAT or change address. Each server makes its own key pair, only public keys are exchanged, and the tunnel carries nothing but DNS. That's how we'll add locations.

Testing

A Docker lab runs the same configuration as production: the primary, four nameservers (one on a separate network, reachable only through the WireGuard tunnel) and a stand-in customer DNS server. Fourteen end-to-end tests check, among other things, that new zones, changes and deletions reach every nameserver, that DNSSEC validates, that secondary DNS follows a customer's edits, and that query counts are exact. Further checks confirm that the primary answers only NOTIFY from untrusted addresses, that the tunnel carries only DNS, and that the nameservers keep answering when the primary is stopped.

What it costs

Right now, nothing. The two nameservers are Oracle Cloud Always Free virtual machines in Ashburn, Virginia, each with 1 GB of memory, and the primary shares the first one. This website is on GitHub Pages, and its contact form uses Web3Forms' free plan.

That's also the main limitation: both nameservers are in the same Oracle data center. A nameserver on another network costs about $4 to $6 a month, and with the tunnel above, adding one takes a few commands.

Want a second set of nameservers?

rtpdns is in early access: we set up customers by hand while we build the dashboard, API and billing.

Request early access