Skip to content

DNS

In the network stack we said every machine has an IP address like 203.0.113.10. But nobody types that. You type example.com. DNS — the Domain Name System — is the phone book that turns human-friendly names into the IP addresses machines actually use. It’s one of the oldest and most load-bearing pieces of the internet, and it has a reputation that every on-call engineer eventually earns: it’s always DNS.

IP addresses are for machines; names are for humans — and, just as importantly, for flexibility. The address behind example.com can change — you move to a new server, a new cloud region, a new load balancer — and as long as the name keeps pointing at the right place, nothing else has to change. That indirection is the whole point. Hard-coding an IP address couples you to a machine; using a name couples you to a service, which is free to move. This is the cure for the fallacy that “topology doesn’t change.”

DNS is a distributed, hierarchical database. No single server knows every name; instead, the question is passed up a chain until someone authoritative answers. When your machine needs the IP for www.example.com:

your app -> "what's the IP for www.example.com?"
|
v
[ Resolver ] (your ISP's or 8.8.8.8) — checks its cache; if missing, asks around:
|
+--> [ Root server ] "ask the .com servers"
+--> [ .com TLD server ] "ask example.com's nameservers"
+--> [ example.com NS ] "www.example.com is 203.0.113.10"
|
v
resolver caches the answer and returns it to you

The resolver does the legwork (this is called recursive resolution). It walks from the root servers, down to the TLD (top-level domain, like .com) servers, down to the domain’s own authoritative nameservers, which hold the real answer. You only ask once; the resolver handles the chain. Most of this runs over UDP — fast, fire-and-forget, exactly the use case from the last page.

A DNS zone is a collection of records. The ones you’ll actually touch:

RecordMapsExample
Aname → IPv4 addressexample.com → 203.0.113.10
AAAAname → IPv6 addressexample.com → 2001:db8::10
CNAMEname → another name (alias)www.example.com → example.com
TXTname → arbitrary textdomain verification, SPF/DKIM email auth
MXname → mail serverwhere email for this domain goes
NSname → authoritative nameserverwho’s in charge of this zone

A/AAAA are the destinations. A CNAME is an alias — “this name is really that other name, go look it up” — which is how you point www.example.com at a load balancer’s name without caring about its IP. TXT records look humble but do heavy lifting: proving you own a domain (for TLS certificates, in HTTP & TLS) and authenticating email so your messages aren’t marked spam.

Walking the whole chain for every lookup would be absurdly slow, so every record carries a TTL (Time To Live) — how many seconds it may be cached before being looked up again. Resolvers, operating systems, and even browsers all cache. A TTL of 3600 means “trust this answer for an hour.”

Caching is what makes DNS fast. It’s also what makes DNS treacherous:

You change example.com from OLD-IP to NEW-IP
|
Authoritative server: updated instantly
|
Resolvers worldwide: still serving OLD-IP until their cached TTL expires
|
Result: some users hit the new server, some the old, for up to TTL seconds

This lag is DNS propagation, and it’s why a change can look broken for hours. The defensive move: lower the TTL well before a planned migration (say, to 60 seconds a day ahead), so when you flip the record, the world catches up in a minute instead of a day.

dig is the precise, scriptable DNS query tool every DevOps engineer should know cold.

Terminal window
dig example.com # the A record(s) — the default question
dig example.com +short # just the answer, no ceremony
dig AAAA example.com # ask specifically for IPv6
dig MX example.com # where does this domain's email go?
dig example.com @8.8.8.8 # ask a specific resolver (Google's), bypassing yours
dig example.com +trace # walk root -> TLD -> authoritative yourself

The @8.8.8.8 trick is gold during an incident: if dig @8.8.8.8 returns the right answer but your machine doesn’t, the problem is your resolver or cache — not the DNS records themselves. +trace lets you watch the full delegation chain, which turns the abstract diagram above into something you can see.

nslookup is the older, more interactive equivalent — more universally installed (it ships on Windows too), less precise. dig example.com and nslookup example.com answer the same question; reach for dig when you need detail and scripting, nslookup for a quick check on a strange machine.

Step back from how the lookup walks the hierarchy and answer the five questions that decide whether DNS is the right indirection:

  • Why does it exist? Because IP addresses are for machines and names are for humans — but the deeper reason is indirection: a name lets the IP behind example.com move (new server, region, load balancer) while everything pointing at the name stays put.
  • What problem does it solve? Coupling. Hard-coding an IP binds you to a machine; a name binds you to a service that’s free to relocate — the cure for the “topology doesn’t change” fallacy, replacing the old hand-copied hosts file with a live, delegated, cached lookup.
  • What are the trade-offs? Caching is what makes DNS fast and treacherous: every record’s TTL buys speed but means a change isn’t global until resolvers worldwide expire their copies — propagation lag of up to TTL seconds where some users hit the new IP and some the old.
  • When should I avoid it? Almost never for naming — but don’t trust it for strong consistency: it’s eventually-consistent and globally cached, so a flag-flip you need instant and atomic (instant failover with a week-long TTL still cached) won’t behave. Lower the TTL before you need the agility.
  • What breaks if I remove it? Everything — DNS sits in front of everything, which is exactly why “it’s always DNS.” Lose it (the Dyn/Mirai attack) and browsers can’t turn twitter.com into an IP, so perfectly healthy servers might as well not exist; the defense is multiple independent providers.
  1. Why use names instead of hard-coding IP addresses? Which fallacy of distributed computing does this defend against?
  2. Walk a fresh lookup for shop.example.com from your resolver to the authoritative answer. What does the resolver do that you don’t have to?
  3. What’s the difference between an A record and a CNAME? When would you reach for each?
  4. Explain DNS propagation. Why should you lower a record’s TTL before a planned migration rather than after?
  5. During an incident, dig @8.8.8.8 api.example.com returns the correct IP but your laptop can’t reach the service. What does that tell you about where the problem is?
Show answers
  1. Names give indirection: the IP behind a name can change (new server, region, or load balancer) while the name stays put, so nothing downstream breaks. Hard-coding an IP couples you to a machine; a name couples you to a service that’s free to move. This defends against “topology doesn’t change.”
  2. The resolver walks the hierarchy for you — asking a root server (which delegates to .com), then the .com TLD servers (which delegate to example.com’s nameservers), then the authoritative nameservers for the real answer — then caches it. You ask once; it handles the whole recursive chain.
  3. An A record maps a name directly to an IPv4 address (a destination); a CNAME is an alias that maps a name to another name to look up. Use an A record for the actual endpoint; use a CNAME to point www at, say, a load balancer’s name without caring about its IP.
  4. Propagation is the lag while resolvers worldwide keep serving a record’s old value until their cached TTL expires, even though the authoritative server updated instantly. Lower the TTL before a migration (e.g. to 60s a day ahead) so that when you flip the record, the world catches up in a minute instead of being stuck on the old TTL for hours.
  5. The DNS records are correct (a public resolver returns the right IP), so the problem is on your side — your local resolver or DNS cache is stale or misconfigured, not the zone itself.