DNS is invisible until it breaks. Then everything breaks. Understanding how DNS works helps you debug issues faster and configure services correctly.

The Basics

DNS translates human-readable names to IP addresses:

example.com93.184.216.34

The resolution process:

12345.....BOQRArSuenoesswcrowshyleeevrrcgekorccseahsqceiuhctteeksordsiccealaostocnchfreaeioalgocuthcraeslcdeehrverveeelsrosblavseerTdL(Doen.sgeT.rT,vLe8r.s8.8.a8u)thoritativeservers

Record Types

A Record (IPv4 Address)

example.com.300INA93.184.216.34

Maps a name to an IPv4 address.

AAAA Record (IPv6 Address)

example.com.300INAAAA2606:2800:220:1:248:1893:25c8:1946

Maps a name to an IPv6 address.

CNAME (Canonical Name)

wbwlwo.ge.xeaxmapmlpel.ec.ocmo.m.330000IINNCCNNAAMMEEehxoasmtpilneg..cpormo.vider.com.

Alias pointing to another name. The resolver follows the chain.

Limitations:

  • Can’t coexist with other records at the same name
  • Can’t be used at zone apex (example.com)

MX (Mail Exchange)

eexxaammppllee..ccoomm..330000IINNMMXX1200mmaaiill12..eexxaammppllee..ccoomm..

Where to deliver email. Lower priority number = preferred.

TXT (Text)

e_xdammaprlce..ecxoamm.ple.c3o0m0.I3N00TXITN"TvX=Tspf1"ivn=cDlMuAdReC:1_;sppf=.rgeojoegclte".com~all"

Arbitrary text. Used for SPF, DKIM, DMARC, domain verification.

NS (Name Server)

eexxaammppllee..ccoomm..8866440000IINNNNSSnnss12..pprroovviiddeerr..ccoomm..

Authoritative name servers for the domain.

SRV (Service)

_http._tcp.example.com.300INSRV10580www.example.com.

Service location. Used by some protocols (LDAP, SIP, XMPP).

Querying DNS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Basic query
dig example.com

# Specific record type
dig example.com MX
dig example.com TXT
dig example.com AAAA

# Query specific nameserver
dig @8.8.8.8 example.com

# Trace the full resolution path
dig +trace example.com

# Short output
dig +short example.com

nslookup

1
2
nslookup example.com
nslookup -type=MX example.com

host

1
2
host example.com
host -t MX example.com

TTL (Time To Live)

How long resolvers cache the record:

example.com.30T0TLinINseconAds(593m.i1n8u4t.e2s1)6.34

Trade-offs:

  • Low TTL (60-300s): Fast updates, more DNS queries
  • High TTL (3600-86400s): Fewer queries, slow updates

Before migrations:

  1. Lower TTL days in advance
  2. Make the change
  3. Wait for old TTL to expire
  4. Raise TTL again

Common Patterns

Multiple A Records (Round Robin)

aaapppiii...eeexxxaaammmpppllleee...cccooommm...666000IIINNNAAA111000...000...111...123

Basic load distribution. Not true load balancing — no health checks.

Failover with Health Checks

Use a DNS provider with health checks (Route 53, Cloudflare):

PSreicmoanrdya:ry:aappii..eexxaammppllee..ccoomm1100..00..12..11((hfeaailltohvecrheicfk:pr/ihmeaarlythu)nhealthy)

GeoDNS

Return different IPs based on user location:

UUUssseeerrriiinnnUEASUsiaaappaiip..iee.xxeaaxmmappmllpeel..ecc.oocmmomuesua--pew-aesssottu..tsshee.rrsvveeerrrvsse..rccsoo.mmcom

Split Horizon DNS

Different answers for internal vs external queries:

IEnxtteerrnnaall:network:ddbb..eexxaammppllee..ccoomm1(0n.o0.r1e.c5o0rd(porrivdaitfefeIrPe)ntIP)

AWS Route 53

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# Create hosted zone
aws route53 create-hosted-zone --name example.com --caller-reference $(date +%s)

# List records
aws route53 list-resource-record-sets --hosted-zone-id Z1234567890

# Add/update record
aws route53 change-resource-record-sets --hosted-zone-id Z1234567890 \
  --change-batch '{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "api.example.com",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [{"Value": "10.0.1.1"}]
      }
    }]
  }'

Debugging DNS Issues

Check propagation

1
2
3
4
# Query multiple public resolvers
dig @8.8.8.8 example.com +short
dig @1.1.1.1 example.com +short
dig @9.9.9.9 example.com +short

Or use online tools: dnschecker.org, whatsmydns.net

Check authoritative servers directly

1
2
3
4
5
# Find authoritative nameservers
dig NS example.com +short

# Query them directly
dig @ns1.provider.com example.com

Check for DNSSEC issues

1
2
dig example.com +dnssec
dig +trace +dnssec example.com

Common problems

Stale cache:

1
2
3
4
5
6
# Flush local DNS cache
# macOS
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

# Linux (systemd-resolved)
sudo systemd-resolve --flush-caches

Wrong nameservers at registrar:

1
2
# Check what nameservers are registered
whois example.com | grep -i "name server"

CNAME at apex:

#e#exxaammIpVpnlalvelea.i.lcdcio:odmm:.U.sCeNAAMCLAENIAAaMStE/A9zN3oA.nM1eoE8t4ah(.pep2err1x.o6cv.oi3md4.er-specific)orArecords

Email DNS Records

SPF (Sender Policy Framework)

example.com.TXT"v=spf1include:_spf.google.cominclude:sendgrid.net~all"

Specifies which servers can send email for your domain.

DKIM (DomainKeys Identified Mail)

selector._domainkey.example.com.TXT"v=DKIM1;k=rsa;p=MIGfMA0..."

Cryptographic signature for email authentication.

DMARC (Domain-based Message Authentication)

_dmarc.example.com.TXT"v=DMARC1;p=reject;rua=mailto:dmarc@example.com"

Policy for handling SPF/DKIM failures.

Terraform Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
resource "aws_route53_zone" "main" {
  name = "example.com"
}

resource "aws_route53_record" "www" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "www.example.com"
  type    = "A"
  ttl     = 300
  records = ["10.0.1.1"]
}

resource "aws_route53_record" "api" {
  zone_id = aws_route53_zone.main.zone_id
  name    = "api.example.com"
  type    = "A"

  alias {
    name                   = aws_lb.api.dns_name
    zone_id                = aws_lb.api.zone_id
    evaluate_target_health = true
  }
}

DNS is foundational infrastructure. Changes propagate slowly (respect TTLs), mistakes affect everyone (email, web, APIs), and debugging requires understanding the resolution chain.

Lower TTLs before changes. Test with dig against authoritative servers. Monitor for DNSSEC issues. The outage that looks like “the server is down” is often DNS — check it first.