New usersFree DNS and CDN plans for every new account.Create your account

How Our DNS Picks Nameservers for Your Zone

Every zone hosted on Yeap DNS gets a pair of nameservers. That pair has to be stable, spread out, and actually able to answer. How our hash-based allocation works, and why "status is intent, heartbeat is fact".

When you add a domain to Yeap DNS, the console gives you two nameservers (NS) to set at your registrar so the domain is delegated to us. It looks like a simple step, but several requirements have to hold at the same time. This post explains how we choose those two nameservers.

Three requirements

  1. Stable. Nameservers are written into the delegation records at your registrar and the TLD registry. If a zone got A and B today and C and D tomorrow, you would have to keep editing registrar settings, and resolution could break in between. For a given zone, the result must be deterministic.
  2. Spread out. If every zone got the same pair, load would concentrate on a few nodes, and a problem with one nameserver would affect everyone. Different zones should land on different combinations.
  3. Actually able to answer. There must be running nodes behind the nameservers you are given. Delegating a zone to a nameserver with no nodes behind it sends queries into a void.

The pool model

Like many hosted DNS services, our model has three layers:

  • Pools: a set of nameservers. Each plan points to a pool, and the free and paid plans use separate pools.
  • Nameservers: each entry in a pool is one NS hostname, the name you eventually enter at your registrar.
  • Nodes: the machines that actually run the authoritative DNS service. A nameserver can be served by several nodes, and its glue records point at those nodes' addresses.

Allocating nameservers for a zone means choosing two nameservers from the pool attached to the zone's plan.

Stable randomness: sorting by a zone-seeded hash

To be both stable and spread out, we use a classic technique that is essentially highest random weight hashing (rendezvous hashing, HRW):

  1. For each nameserver in the pool, compute hash(zoneName + ":" + nameserverId);
  2. sort by that hash (falling back to the ID on ties, so the order is always deterministic);
  3. take the first two.
function pickNameservers(pool, zoneName, count = 2):
    if len(pool) <= count:
        return pool
    sort pool by (crc32(zoneName + ":" + ns.id), ns.id)
    return first count items of pool

This has some useful properties:

  • Deterministic: the only inputs are the zone name and the pool contents. The same zone gets the same answer however many times you compute it, with no dependence on random state or on load at the moment of allocation.
  • Evenly spread: different zones get different, random-looking orderings, so overall they spread evenly across the nameserver combinations in the pool.
  • Small blast radius when growing: adding a nameserver to a pool only changes the result for zones where the newcomer happens to rank in the top two; every other zone's result is unchanged. That is the main advantage of HRW over simple modulo hashing.

Note that the result is stored when the zone is created. Later changes to a pool do not automatically change the nameservers of existing zones, so your delegation never shifts because we added capacity. Where determinism really pays off is that a zone created through any path (the console, the API, or automatic provisioning after you buy a plan) goes through the same allocator and gets the same answer.

When there is no zone name to use as a seed (a few rare internal paths), the allocator falls back to "fewest hosted zones first", a deterministic form of load balancing.

Status is intent, heartbeat is fact

Before sorting, there is a more important step: deciding which nameservers are allowed into the candidate pool at all. We call these servable, and a nameserver must satisfy all of the following:

  • the nameserver itself is enabled;
  • it has a valid NS hostname (not empty and not a placeholder used for testing);
  • at least one node is bound to it whose status is enabled and which has sent a heartbeat within the last 15 minutes.

The last condition deserves a closer look. A node's status field in the database is set by an operator; it expresses "we want this node to be serving". Wanting is not the same as reality. A machine can be marked enabled and yet have stopped answering long ago because it was reinstalled, its network changed or its credentials went stale. An allocator that trusted the status field alone could delegate new zones to a service that does not really exist.

So our rule is: the status field is intent; the heartbeat timestamp is fact. Each node refreshes its last-seen time every time it polls for configuration, and nodes that stop polling are automatically marked offline after a while. The allocator only trusts facts.

How nodes get your zone data

Once allocated, the zone's data has to appear on the right nodes. Our authoritative DNS data plane is a customized build of CoreDNS that works in pull mode:

  • Each zone has a configuration version, which is also the serial number in the zone's SOA record. Any record change increments it.
  • Nodes periodically ask the control plane, with authentication, for current versions. When a version changes, they fetch the new zone data, write it out as a standard zone file and reload.
  • Each node only receives the zones assigned to the nameservers it serves, not the full data set.
  • When a zone is disabled or deleted, the control plane keeps sending a deletion signal to nodes for a period of time, and nodes remove the local zone file and stop answering for it. Deleted zones do not linger on some nodes.

Because the SOA serial is the configuration version, you can check with dig whether a given nameserver has the latest version:

dig +short SOA example.com @your-nameserver-hostname

If every nameserver returns the same serial, they all have the latest data.

A lesson about infrastructure zones

The NS hostnames themselves need to resolve too, and their glue and address records live in a dedicated infrastructure zone managed by the same system as customer zones. That means its status must always stay enabled: if it were ever disabled by mistake, the deletion signal would cause nodes to drop it, and every zone relying on those nameservers would be affected. We specifically checked for this in end-to-end testing before turning on deletion signals, and such zones are now marked as permanently resident.

The lesson applies to any self-hosting system: when your platform hosts its own critical dependencies, those dependencies need extra protection.

What you need to do

As a user, all you need to do after adding a domain is set the two nameservers shown in the console at your registrar. The zone's detail page shows which nameservers are assigned to it and how many active nodes each one currently has, and the console's NS check tells you when the delegation has taken effect. The allocator and the sync pipeline handle the rest.

Build on Yeap Cloud

Free DNS and CDN plans for every new account.

Sign up free