NetworkingBeginner

How DNS actually works

Nothing in DNS propagates. A name is resolved by walking down from the root, and every answer is a cached copy with an expiry date you set yourself.

Assumes you know

  • That a server somewhere has an IP address
  • What an HTTP request is

Ask a public DNS server for wikipedia.org twice, three seconds apart, and both answers carry the same address and a different number beside it:

103.102.166.224   ttl 23
103.102.166.224   ttl 20

Nothing about Wikipedia changed in those three seconds. The number is not part of the address and it is not a measurement of anything. It is how much longer the server you asked is willing to hand out the copy it is already holding. When it reaches zero, that copy is thrown away and the next person to ask causes a real lookup.

Why DNS is shaped like this

Build it up

/etc/hosts

104.21.14.225   techdecoded.dev
93.184.215.14   example.com

Without this

Every new host means somebody edits a file on every other computer, by hand.

This is not a thought experiment. The file still exists on your machine.

1 / 4

Each step fixes what the last one broke, and no step puts the full list in one place.

/etc/hosts is still on your machine, it still works, and it still wins: if a name is in that file, your computer never asks anyone. That is useful when you want to point a domain at your own laptop, and it is a genuinely nasty thing to forget about when a colleague cannot reproduce what you are seeing.

The root servers have never heard of your domain and are not supposed to. That means there is no central copy to publish, no master database to synchronise, and nowhere for a change to be pushed out from.

One lookup, run against the real servers

Every message below was captured from the real servers, starting at a root server’s address.

Sequence

Your resolverrecursive
A root server198.41.0.4
The .dev registryns-tld1.charlestonroadregistry.com
Cloudflarekyle.ns.cloudflare.com
techdecoded.dev A?
Ask .dev
techdecoded.dev A?
Ask Cloudflare
techdecoded.dev A?
104.21.14.225

1 / 6

Three questions. Two of the answers were not answers.

The thing doing the walking is called a , and it is almost never your own machine. Your laptop asks one server a single question and gets one answer, which is why a lookup looks atomic from where you are standing.

Only the last server in that chain is . The records it holds for one domain, managed together as a unit, are that domain’s .

The root’s referral is good for 172,800 seconds, which is two days. The registry’s is good for three hours. The address itself is good for five minutes. Parts of the chain that rarely change are cached for a long time, and the part you edit is cached briefly, which is a choice somebody made rather than a property of the network.

There are 13 root server addresses, lettered a through m, operated by 12 organisations, and a little over 2,000 server instances answer on those 13 addresses. “The root” is a set of addresses, not a set of computers.

What a record actually is

Anatomy

One A record, as the authoritative server returned it

NameThe trailing dot is the root of the tree. Every name in DNS really ends with it; your browser and your resolver let you leave it off.

The expiry is a field in the record, not something a cache added later.

A record sitting at a TTL of 86,400 has already committed you to a day of waiting before you have decided to change anything, and there is nothing you can do at the moment of the change to shorten it. You pick that number long before you need it, usually without noticing you are making a decision at all.

The record types you will actually meet

TypeValue looks likeWhat it is for
A104.21.14.225An IPv4 address for this name.
AAAA2606:4700:3032::6815:ee1An IPv6 address for this name.
CNAMEgithub.com.This name is an alias. Go and look up that one instead.
MX10 inbound-smtp.us-east-1.amazonaws.com.Where to deliver mail for this domain. The number is a priority, lowest first.
TXT"google-site-verification=GiDb..."Arbitrary text. Used for domain ownership proofs and mail policy.
NSkyle.ns.cloudflare.com.Which nameservers are authoritative for this name.

A CNAME is the one with a rule attached. Look at what a real one returns:

www.github.com.  2417  IN  CNAME  github.com.
github.com.        40  IN  A      20.207.73.82

The resolver asked for an address, got told “that name is really this other name”, and went and resolved that instead. You get both records back because it did both lookups.

The rule is that a CNAME must be the only data at its name. RFC 1034 puts it plainly: “If a CNAME RR is present at a node, no other data should be present.” An alias is a redirection of the entire name, so anything else sitting there would be contradicted.

That collides with the . The apex has to carry an NS record, because that is how anybody finds your nameservers at all, and an SOA record. Both of those are data. So a CNAME cannot sit there, and every DNS provider’s control panel will refuse you.

Providers sell a way around it under names like ALIAS, ANAME or CNAME flattening. You type a hostname; their nameserver resolves it itself and answers queries with ordinary A and AAAA records. No resolver ever sees a CNAME at your apex, so no rule is broken and your MX and TXT records keep working. Cloudflare’s flattening and Route 53’s alias records are the two you are most likely to meet.

Check yourself

You want example.com (no www) to point at a CDN hostname like d1234.cloudfront.net. Your provider refuses to save a CNAME on the bare domain. Why?

Who is holding a copy

Stack

A lookup stops at the first layer holding a copy that has not expired.

You can clear the top two layers yourself and you cannot touch the third. That asymmetry is what makes “it works on my machine” so common here: flushing your browser and your operating system fixes your own view and changes nothing for anybody else, including the resolver you and your colleague share.

Check yourself

You change your site's A record at 14:00. The record's TTL was 3600. At 14:30 a colleague in another country still loads the old site. What is happening?

Changing a record without a wait

Since the wait is other people’s copies timing out, you can remove it by making those copies short-lived before you touch anything that matters.

Timeline

  1. 09:00

    Lower the TTL to 60

    3600 seconds

    Change nothing else. This is invisible to the world: caches are holding copies stamped 3600 and will honour that number.

  2. 10:00

    The last old copy expires

    3600 seconds

    One full old TTL after the edit. Every cache has now refetched, and what they are holding says 60.

  3. 10:00today

    Change the address

    60 seconds

    The only step that touches the thing you actually came to change.

  4. 10:01

    Nobody is on the old address

    60 seconds

    One new TTL later. Not "most people". Nobody, because no copy older than 60 seconds exists.

  5. 11:00

    Put the TTL back to 3600

    3600 seconds

    A 60 second TTL means every cache re-asks your nameservers every minute. Fine for an afternoon, wasteful forever.

The change takes a second. The two waits either side of it are the work.

If you did not plan ahead, there is no button to press: you wait one old TTL. Anyone telling you to allow 24 to 48 hours is quoting folklore from an era of much longer default TTLs, and you can check the real figure by asking for the record and reading the number that comes back.

The traps

“Does not exist” is cached too. Ask for a name that is not there and you do not get silence, you get a refusal with an expiry on it, called :

nope-not-here.techdecoded.dev.  NXDOMAIN
techdecoded.dev.  1800  IN  SOA  kyle.ns.cloudflare.com. dns.cloudflare.com.
                                 2413665214 10000 2400 604800 1800

That trailing 1800 in the SOA record is what caps how long resolvers may remember the absence, a mechanism defined in RFC 2308. So if you or anyone else looked up a subdomain before you created it, the negative answer is sitting in a cache and your brand new record will not be seen until it expires. This catches people setting up certificate validation records, where the tooling checks for the record, fails, and then keeps failing for half an hour after you have added it.

The TTL is per record, not per domain. On this site’s zone right now the A record has a TTL of 300, the MX has 3600, and the NS has 86400. Changing where mail goes and changing where the website points are two different waits.

/etc/hosts is not DNS and does not care about any of this. It is consulted before a lookup happens, so a stale line in it will survive every cache flush and every TTL you have ever set.

Check yourself

You look up api.example.com, get NXDOMAIN, then immediately create the record with a TTL of 60. You look it up again a minute later and still get NXDOMAIN. Why?

What DNS will not do for you

It does not route anything. Handing back an address is the end of the job. What happens to the packet afterwards is routing, and DNS has no involvement in it.

It does not know whether your server is up. A nameserver returns what the zone says, whether or not anything is listening at that address. Health checking is a product some managed DNS providers sell on top, where their systems probe your servers and edit the zone for you. Plain DNS has no concept of up or down.

It is a poor load balancer. You can put several addresses on one name, and clients end up spread across them, but caching means you cannot control which client gets which address or shift traffic away from one quickly when you need to.

It is not private and it is not authenticated. Classic DNS is unencrypted, usually over UDP port 53, so the names you look up are readable by anything on the path, and anyone positioned to reply before the real nameserver does can lie to you. DNS over HTTPS and DNS over TLS address the first problem, DNSSEC addresses the second, and both are separate topics. Worth knowing when reading how SSL actually works: HTTPS hides the page you asked for, but the DNS lookup that preceded it announced the hostname in the clear.

Checking your work

Ask your own machine what it resolves a name to, and how it got there:

resolvectl query techdecoded.dev
techdecoded.dev: 104.21.14.225
                 172.67.204.137
                 2606:4700:3032::6815:ee1
                 2606:4700:3030::ac43:cc89

-- Information acquired via protocol DNS in 60.7ms.
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
-- Data from: network

That gives you addresses but not the TTL. To see the countdown, ask a resolver over HTTPS, which returns the raw fields as JSON:

curl -sH 'accept: application/dns-json' \
  'https://cloudflare-dns.com/dns-query?name=techdecoded.dev&type=A'
{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,
 "Question":[{"name":"techdecoded.dev","type":1}],
 "Answer":[{"name":"techdecoded.dev","type":1,"TTL":300,"data":"104.21.14.225"},
           {"name":"techdecoded.dev","type":1,"TTL":300,"data":"172.67.204.137"}]}

The tool most guides reach for here is dig, which comes in the dnsutils package on Debian and Ubuntu and bind-utils on Fedora and RHEL. It prints the same fields in the classic zone-file layout, and dig +trace walks the chain from the root the way the sequence above does.

Try it yourself

~2 min

Watch a TTL run out

Ask for the same name twice in a row and compare the TTL field:

curl -sH 'accept: application/dns-json' \
  'https://cloudflare-dns.com/dns-query?name=wikipedia.org&type=A'
# wait a few seconds, then run it again

Then ask for a name that does not exist, and look at what comes back instead of an address:

curl -sH 'accept: application/dns-json' \
  'https://cloudflare-dns.com/dns-query?name=nope-not-here.wikipedia.org&type=A'
What you should see

The TTL in the second lookup is lower by roughly the number of seconds you waited. You are watching one resolver’s copy age. If it jumps back up instead, you reached a different machine behind the same address, holding its own copy on its own clock.

The name that does not exist returns "Status": 3, which is NXDOMAIN, and an Authority section containing an SOA record rather than an Answer section. The last number in that SOA is how many seconds resolvers may remember that this name is missing. That is the number standing between you and a record you are about to create.

Where to go next

Point a domain at a CDN and you are making a DNS change and nothing else, which is worth reading alongside what a CDN actually does: the cache key section there is the same “who is holding a copy” reasoning one layer up the stack.

The specifications are unusually readable for their age. RFC 1034 is the concepts, published in November 1987 and still accurate. RFC 2308 is negative caching, and it is short.

The obvious next question is how you know an answer was not tampered with in transit, given that anyone who can reply faster than the real nameserver wins. That is DNSSEC, and it deserves its own article.

If you remember nothing else

  • Nothing in DNS is pushed. Every answer is one somebody asked for, and the only reason lookups are fast is that whoever asked before you kept a copy.
  • There is no propagation. When a change has not taken effect, the question is never where the record has got to; it is which cache is still holding an old copy and when its TTL runs out.
  • A TTL is set by the zone owner and obeyed by everyone downstream, so a safe record change means lowering the TTL first, waiting one full old TTL, and only then changing the value.
  • Most servers in a lookup do not know the answer and are not meant to. The root and the registry hand back referrals; only the authoritative nameserver was ever told the address.
  • A CNAME must be the only record at its name, which is why the bare domain cannot have one, and why providers synthesise A records there instead.

Quick answers

How long does DNS propagation take?
There is no propagation, so there is nothing to wait for except caches expiring. A resolver holding a copy will keep serving it for exactly the TTL that copy was handed, then re-ask. If the record had a TTL of 3600 when it was cached, the longest anyone can be stuck on the old value is one hour, no matter what your DNS provider's control panel says about 24 or 48 hours.
Why does dig show the new record but my browser still loads the old site?
Because they are asking different caches. A query tool usually goes straight to a resolver, while a browser checks its own DNS cache first, then the operating system's, then the resolver. Any of those can still be holding an unexpired copy. Browsers also keep HTTP connections alive and cache the page itself, so even a correct lookup does not guarantee a fresh request.
What is the difference between my registrar and my DNS host?
The registrar is who you rent the name from, and the only DNS record they control is the NS record that says which nameservers are in charge. That record lives in the TLD's zone, one level above yours. The DNS host runs those nameservers and holds everything else: your A, MX, TXT and the rest. If the world cannot find your domain at all, check the NS delegation at the registrar before you look at any individual record.
Why can I not put a CNAME on my bare domain?
RFC 1034 says that if a CNAME is present at a name, no other data may be present at that name. The bare domain necessarily carries SOA and NS records, so a CNAME cannot legally sit alongside them. Providers work around it with names like ALIAS, ANAME or CNAME flattening: you type a hostname, and their nameserver resolves it and answers with plain A and AAAA records, so no resolver ever sees a CNAME there.
Does DNS know when my server goes down?
No. A nameserver hands back whatever the zone says, and it has no idea whether anything is listening at that address. Managed DNS providers sell health checking as a product layered on top, where their own systems probe your servers and edit the zone for you, but plain DNS has no concept of a server being up or down.