DNS concepts, record types, and management skill: Cloudflare, Route 53, DNSSEC, debugging with dig/nslookup, TTL strategy, and split-horizon DNS. USE WHEN: - Adding or modifying DNS records for a web application, mail system, or API - Configuring Cloudflare proxy (orange cloud) or DNS-only mode - Setting up Route 53 hosted zones, health checks, and routing policies - Debugging DNS propagation, CNAME loops, MX failures, or SPF/DKIM issues - Planning a migration with minimal downtime (TTL strategy) - Configuring DNSSEC, CAA records, or reverse DNS (PTR) - Setting up split-horizon DNS for internal vs external resolution DO NOT USE FOR: - SSL/TLS certificate issuance (use ssl-tls skill) - Nginx or application-level routing (use nginx or api-gateway skill) - Service mesh internal DNS (use kubernetes or service-mesh skill) - Email server configuration beyond DNS records (use a dedicated email skill)

GitHub
安装命令
npx skhub add claude-dev-suite/dns
Markdown
SKILL.md

DNS — Concepts, Records, and Management

Record Type Reference

TypeFormatExample valueUse caseKey notes
AIPv4 address93.184.216.34Map hostname to IPv4Most common record; can have multiple values for round-robin
AAAAIPv6 address2606:2800:220:1:248:1893:25c8:1946Map hostname to IPv6Dual-stack: both A and AAAA on same name
CNAMEFully-qualified hostnamemyapp.netlify.app.Alias one name to anotherCannot be used at zone apex; trailing dot = absolute FQDN
MXPriority + hostname10 mail.example.com.Mail server routingLower priority number = higher preference; hostname must resolve via A/AAAA
TXTQuoted string"v=spf1 include:_spf.google.com ~all"SPF, DKIM, DMARC, domain ownership verificationMultiple TXT records on same name are valid
SRVPriority Weight Port Target10 5 5060 sip.example.com.Service discovery (SIP, XMPP, game servers)Format: _service._proto.name e.g. _sip._tcp.example.com
CAAFlags Tag Value0 issue "letsencrypt.org"Restrict which CAs can issue certs for domainProtects against misissued certificates
PTRFully-qualified hostnamehost.example.com.Reverse DNS (IP → hostname)Managed in in-addr.arpa zone; controlled by IP owner (ISP/cloud provider)
NSNameserver hostnamens1.cloudflare.com.Authoritative nameservers for zoneSet at registrar; changes propagate slowly (24-48h)
SOASerial Refresh Retry Expire Minimum(auto-managed)Zone metadata; used in AXFR transfersSerial must increment on every change for NOTIFY to work
ALIAS / ANAMEHostnamemyapp.netlify.app.Apex CNAME equivalentCloudflare: CNAME Flattening; Route 53: ALIAS record; resolves at zone apex
DSKey tag Algorithm Digest type Digest12345 13 2 ABC123...DNSSEC — links parent zone to child zone signing keyCreated in parent zone; references KSK in child

TTL Strategy

TTL (Time to Live, in seconds) controls how long resolvers cache a record. Higher TTL = fewer queries to your nameservers; lower TTL = faster propagation of changes.

Standard TTL Values

TTLSecondsUse case
1 minute60Active incident response / testing
5 minutes300Pre-migration staging
1 hour3600Default for most records
1 day86400Stable records (MX, NS)
1 week604800Static infrastructure

Migration TTL Strategy (Zero-Downtime Record Change)

Day -7:   Lower TTL of the record from 86400 to 300 (5 minutes)
          Wait for caches to expire (1 full day at old TTL = 86400s)

Day 0:    Change the record to the new value
          Old value expires from caches within 300s (5 minutes)
          New value takes effect almost immediately

Day +1:   Restore TTL to 86400 once confident in new value

This pattern ensures no resolver is caching the old value when you make the switch.


Cloudflare Setup for a Typical Web App

# Step-by-step zone configuration sequence

1. Add site to Cloudflare (free plan works for most apps)
   → Cloudflare scans existing records (import them)

2. Update NS records at your registrar to point to Cloudflare nameservers:
   ns1.cloudflare.com
   ns2.cloudflare.com
   (NS propagation: 24-48h)

3. Configure records in Cloudflare dashboard:

   Type  Name    Content              Proxy status   TTL
   A     @       93.184.216.34        Proxied (🟠)   Auto
   A     www     93.184.216.34        Proxied (🟠)   Auto
   CNAME api     backend.example.com  Proxied (🟠)   Auto
   MX    @       10 mail.example.com  DNS only (⬜)  Auto
   TXT   @       v=spf1 ...           DNS only (⬜)  Auto
   TXT   _dmarc  v=DMARC1; ...        DNS only (⬜)  Auto

4. SSL/TLS mode: Full (strict) — requires valid cert on origin
   Security > Settings: Enable HSTS (after app is stable)
   Speed > Optimization: Enable Brotli compression

5. Page rules (legacy) or Rules > Redirect rules:
   http://example.com/* → https://example.com/$1 (301)

Cloudflare Proxy (Orange Cloud) vs DNS-Only (Grey Cloud)

SettingIP exposedDDoS protectionCloudflare CDN/cacheWebSocketsUse when
Proxied (orange)Cloudflare IPs shownYesYesSupportedPublic web, APIs, static sites
DNS-only (grey)Origin IP exposedNoNoN/AMail (MX targets must be DNS-only), non-HTTP services, internal servers

Important: A record being proxied hides your origin IP, but only if you never expose your origin IP elsewhere (e.g., in certificate transparency logs, email headers, or old DNS records).


Route 53 — Key Concepts

# Install AWS CLI v2
pip install awscli --upgrade
aws configure  # Set AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region

# List all hosted zones
aws route53 list-hosted-zones --output table

# Get hosted zone ID for example.com
ZONE_ID=$(aws route53 list-hosted-zones-by-name \
    --dns-name example.com \
    --query 'HostedZones[0].Id' \
    --output text | cut -d/ -f3)

# Upsert a record using change batch JSON
aws route53 change-resource-record-sets \
    --hosted-zone-id "$ZONE_ID" \
    --change-batch '{
        "Changes": [{
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "api.example.com",
                "Type": "A",
                "TTL": 300,
                "ResourceRecords": [{"Value": "93.184.216.34"}]
            }
        }]
    }'

# Create an ALIAS record (apex CNAME equivalent) pointing to an ALB
aws route53 change-resource-record-sets \
    --hosted-zone-id "$ZONE_ID" \
    --change-batch '{
        "Changes": [{
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "example.com",
                "Type": "A",
                "AliasTarget": {
                    "HostedZoneId": "Z35SXDOTRQ7X7K",
                    "DNSName": "my-alb-123.us-east-1.elb.amazonaws.com.",
                    "EvaluateTargetHealth": true
                }
            }
        }]
    }'

Route 53 Routing Policies

PolicyUse caseNotes
SimpleSingle resourceDefault; no health checks
WeightedA/B testing, canary deploymentsSet weights 0-255; 0 = no traffic
LatencyMulti-region lowest-latency routingAWS measures latency between client and region
FailoverActive-passive HARequires health check on primary record
GeolocationServe different content by country/continentFalls back to default if no match
Multivalue AnswerPoor-man's load balancing with health checksReturns up to 8 healthy records

dig — Complete Command Reference

# Basic query (A record)
dig example.com

# Short output (just the answer)
dig +short example.com
dig +short example.com A

# Query a specific record type
dig example.com MX
dig example.com TXT
dig example.com AAAA
dig example.com NS
dig example.com SOA
dig example.com CAA
dig example.com SRV

# Query a specific nameserver (bypass system resolver)
dig @8.8.8.8 example.com A         # Google Public DNS
dig @1.1.1.1 example.com A         # Cloudflare
dig @ns1.cloudflare.com example.com A  # Query authoritative NS directly

# Trace the full delegation chain from root servers
dig +trace example.com

# Check TXT records (SPF, DKIM, DMARC)
dig +short example.com TXT
dig +short _dmarc.example.com TXT
dig +short mail._domainkey.example.com TXT

# Reverse DNS lookup (PTR)
dig -x 93.184.216.34
dig +short -x 93.184.216.34

# Check DNSSEC chain
dig +dnssec example.com
dig +sigchase example.com A  # Validate DNSSEC chain (requires dig ≥ 9.9)

# Show all sections (answer, authority, additional)
dig +all example.com

# Check propagation against multiple resolvers
for ns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
    echo "--- $ns ---"
    dig @$ns +short example.com A
done

# Query SRV record (format: _service._proto.domain)
dig _https._tcp.example.com SRV

SPF / DKIM / DMARC Quick Reference

SPF TXT record

"v=spf1 ip4:203.0.113.0/24 include:_spf.google.com include:sendgrid.net ~all"
  • ip4: — explicitly authorise IP range
  • include: — include another domain's SPF (counts toward the 10 DNS lookup limit)
  • ~all — soft fail (mark as spam); -all = hard fail (reject)
  • +all — allow all (useless for security)

DKIM TXT record (example with key)

Name:    mail._domainkey.example.com
Value:   "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ..."

Generated by your email provider; p= is the public key.

DMARC TXT record

Name:    _dmarc.example.com
Value:   "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com; pct=100"
  • p=none → monitor only (start here)
  • p=quarantine → send to spam
  • p=reject → reject failing mail (fully enforced)
  • rua= → aggregate report address
  • pct=100 → apply to 100% of mail

Split-Horizon DNS

Split-horizon (or split-brain) DNS returns different answers for the same hostname depending on the source of the query — typically internal vs external.

Implementation with systemd-resolved (Linux client)

# /etc/systemd/resolved.conf.d/split-horizon.conf
[Resolve]
DNS=10.0.0.53          # Internal DNS server for internal zone
Domains=~internal.example.com ~corp.internal

Implementation with Bind9 (server-side)

# /etc/bind/named.conf.local
view "internal" {
    match-clients { 10.0.0.0/8; 172.16.0.0/12; localhost; };
    zone "example.com" {
        type master;
        file "/etc/bind/zones/example.com.internal";
    };
};

view "external" {
    match-clients { any; };
    zone "example.com" {
        type master;
        file "/etc/bind/zones/example.com.external";
    };
};

Internal zone can return private IPs (10.x.x.x) for api.example.com while the external zone returns the public IP or load balancer.


DNS Propagation: How It Works

When you update a record, the authoritative nameserver immediately has the new value. But:

  1. Your ISP's recursive resolver cached the old value for up to TTL seconds.
  2. Other resolvers around the world have their own cached copies.
  3. "DNS propagation" = waiting for all caches to expire their copies.

True propagation time = the TTL that was set before you made the change.

Check propagation across global resolvers:


Anti-Patterns

Anti-patternWhy it's harmfulFix
CNAME at zone apex (@)RFC 1034 violation; breaks NS and SOA records; some resolvers reject itUse ALIAS/ANAME (Cloudflare CNAME Flattening) or Route 53 ALIAS record at apex
TTL too high during migrationOld value cached for days; impossible to roll back quicklyLower TTL to 300s at least one full TTL cycle before any planned migration
No CAA recordAny CA can issue a cert for your domain; misissued certs possibleAdd CAA 0 issue "letsencrypt.org" and optionally CAA 0 iodef "mailto:security@example.com"
SPF with too many DNS lookups (> 10)Receivers fail SPF validation with permerror — mail gets rejected or marked spamFlatten SPF using tools like dmarcian SPF Surveyor; replace include: chains with ip4:/ip6:
DMARC p=none left in place indefinitelyMonitoring-only mode never enforces; DMARC provides no protectionProgress to p=quarantine then p=reject over 2-4 weeks after reviewing aggregate reports
Wildcard *.example.com without base domain recordSubdomain takeover risk; attacker registers a dangling CNAME targetEnsure wildcard doesn't mask legitimate subdomains; add specific records where needed
PTR record not set for mail server IPMany mail servers reject or spam-score mail from IPs without matching PTR (rDNS)Request PTR record from your hosting provider / ISP pointing to mail.example.com
Proxying all records through Cloudflare including mailMX records and their targets must resolve to origin; Cloudflare proxy on MX targets breaks SMTPSet MX records and their A record targets to DNS-only (grey cloud)
NS records changed at both registrar and zoneConflicting NS records cause intermittent resolution failuresNS records at registrar (glue records) must match NS records in the zone; change only at registrar
Changing NS without checking current TTLOld NS cached at resolvers for up to 48h; some queries go to old nameserversLower NS TTL to 300s before changing, or accept 24-48h propagation

Troubleshooting

SymptomLikely causeDiagnostic / Fix
CNAME loopA points to B which points back to Adig +trace example.com; trace the CNAME chain; break the loop at the registrar
MX not resolvingMX target is a CNAME (RFC violation) or MX target has no A/AAAA recordMX must point to a hostname with an A/AAAA record, not a CNAME
SPF "permerror" / too many lookupsChain of include: directives exceeds 10 DNS lookupsCount with MXToolbox SPF check; flatten include: chains to ip4:/ip6:
DKIM verification failureKey mismatch, key too short, or selector name wrongdig +short mail._domainkey.example.com TXT; compare with key in email header DKIM-Signature:
DNS not propagating after record changeResolver still serving cached old valueWait for TTL; test with dig @8.8.8.8 +short name; check TTL was previously lowered
dig +trace shows SERVFAILDNSSEC validation failure, NS record mismatch, or zone transfer issueCheck DS record in parent zone; verify DNSSEC signatures; dig +dnssec +multiline example.com DNSKEY
Subdomain returns wrong IP internallySplit-horizon not configured; internal hosts resolving via public DNSSet internal DNS server for the zone; configure clients to use internal resolver for that domain
NXDOMAIN for www but @ workswww record not added when moving to new DNS providerAdd CNAME www @ or A www <IP> explicitly; import all records when switching
Mail rejected: "550 No PTR record"Sending mail server IP has no reverse DNS (PTR)Request PTR from hosting provider; PTR must match mail server's FQDN
Cloudflare 1xxx error after enabling proxyOrigin IP block, origin firewall blocking Cloudflare IPs, or SSL mode mismatchWhitelist Cloudflare IP ranges on origin; check SSL mode is "Full (strict)" not "Flexible"
发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/infrastructure/dns

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1