Networking
DNS and how a browser finds a website
How a name becomes an address: nameservers, A, AAAA and CNAME, TTL, recursion against authority, and the cache mistakes that keep the old IP.
10 min read
A website name is not an address. example.com is a label. The address is a number, IPv4 or IPv6, and the browser cannot open a connection until something turns the label into that number. The Domain Name System is a tree of zones, served by nameservers, with answers that caches are allowed to keep. The failures that waste an afternoon are a cache, a record on the wrong name, or an edit that never reached the server the world is asking.
This note follows one URL to the address the browser connects to, then stays with the records you publish: A, AAAA, CNAME, the TTL, and a recursive resolver against an authoritative nameserver. Examples use example.com, which IANA operates, and the documentation addresses 203.0.113.10 and 2001:db8::10. Those addresses are for zone files. They are not a host you can put a site on.
What happens when you type a URL
Take https://www.example.com/pricing. The browser splits it into a scheme (https), a host (www.example.com), a port (443, because https was written and no port was), and a path (/pricing). DNS is asked about the host only. The path is sent later, in HTTP, once a connection exists. A record for www.example.com does not publish /pricing. A missing page and a missing name are different errors.
An address typed in the bar, such as https://203.0.113.10/, skips DNS. TLS is still checked against that host, so a certificate for www.example.com will not match. The warning is not a lookup failure.
For a name, the browser wants A records (IPv4) and AAAA records (IPv6). Current browsers do not wait for one family to fail before trying the other. Happy Eyeballs gives IPv6 a short head start, a fraction of a second, then starts IPv4 as well, and uses the connection that completes first. A broken IPv6 address often looks like a slow site, until that attempt gives up. A client with only one family does not get the race. It needs a record it can actually use.
The port does not come from DNS. Browsers do not look up SRV records for ordinary web URLs. HTTPS to www.example.com is port 443 even if some other service published an SRV record. A site on 8443 has to say so in the URL.
The browser then connects and starts TLS. The certificate has to cover the host that was typed. A correct address and a name missing from the certificate are different faults. The nginx note is where that certificate is configured. This one ends when the address is known.
The hosts file, the stub, and a private resolver
The operating system may answer before any nameserver is asked. Linux reads /etc/hosts first when /etc/nsswitch.conf lists files ahead of dns. macOS and Windows do the same with their hosts files. A line there applies to that machine only. It is how a laptop reaches staging without a public record, and how a forgotten staging line hides a DNS change from you alone.
203.0.113.10 www.example.com example.comThe stub resolver does not walk the tree. It sends the query to a recursive resolver and waits. On current Ubuntu that stub is often systemd-resolved on 127.0.0.53, with /etc/resolv.conf pointed at it. resolvectl status shows the upstream: the router, the host, or something you chose such as 1.1.1.1. dig follows this path. A browser might not.
With DNS over HTTPS turned on, the browser can ask that provider itself and skip resolv.conf. A hosts-file line can then show up in dig and not in the address bar. Compare dig, curl, and the address bar. If they disagree, turn the browser's private DNS off and look again.
search and ndots in resolv.conf add a local rewrite. With search example.com and ndots:1, the single label db is tried as db.example.com before it is tried as db. A trailing dot stops that: dig db. is the name as written. Zone files use the same trailing-dot rule.
Recursive resolvers and authoritative servers
Two kinds of server are both called DNS, and they do opposite jobs.
A recursive resolver takes the stub's question. RD on the query means recursion desired. RA on the reply means the resolver accepted that work. A cache hit is answered immediately. A miss starts at the root, follows referrals, and stops at an authoritative server. The result is cached and returned, usually without the AA bit. The recursive server is repeating the zone, for the TTL. It is not the authority.
An authoritative server holds the zone. It sets AA, answers from that data, and will not look up the rest of the world for you. A name outside its zones gets a referral or a refusal. A name inside them comes back with the TTL written in the zone, not a countdown.
dig www.example.com A
dig @a.iana-servers.net example.com AThe first asks your resolver. Expect ra, and an answer whose TTL falls if you run it again. That number is the time left in the cache. The second asks an authoritative server for example.com. Expect aa, and the TTL as published. If they disagree, the zone has moved and a cache still has the old set. Another edit does not push that copy out.
dig +trace example.com A prints the walk from the root, through the TLD, to the authoritative servers. Use it when the panel you edited might not be the one the parent delegates to.
Read the status before the address. NOERROR with records is a hit. NOERROR with none is NODATA: the name exists, this type does not. NXDOMAIN means no such name. SERVFAIL is a dead server, a zone that failed to load, or a DNSSEC check that failed. REFUSED means the server declined the query. A validating resolver can return SERVFAIL for a bad signature while a direct query still shows the record. Check the signatures before republishing an address the authority already returns.
Nameservers, delegation, and glue
Zones are cut at delegations. The parent publishes NS records for the child. For example.com the parent is .com, and the registrar is how you edit that set. The company that hosts the zone holds the addresses and aliases, and it is often a different company. An edit in a panel the parent no longer points at changes nothing for anyone else. dig +trace shows the parent's NS set. dig NS example.com shows what your resolver cached, which can be a day behind.
The two NS sets should match. Resolvers cache the parent's set for the delegation TTL, often a day or two, and the hosting panel does not set that number. A shorter A-record TTL does not speed an NS move.
If the nameserver's name is inside the zone it serves, the parent has to publish the address too. Otherwise the resolver cannot look up ns1.example.com without already knowing it. That parent address is glue, set at the registrar next to the NS hostname. The same address belongs in the zone, and the zone copy does not replace the glue. Change the IP and leave the glue, and resolvers keep the old address for the glue TTL.
A secondary copies the zone and decides whether the copy is newer from the SOA serial. The number has to go up when the data changes. 2026110601 (YYYYMMDDnn) is a common shape. Any larger integer is valid. Panels bump it. A file edited by hand does not. A serial that stays put leaves the secondary on the old zone until the copy expires, so some networks see the new address and some do not.
The last SOA number is the negative-cache TTL. Older texts call the field "minimum". It is not a floor under the other TTLs. It is how long a resolver may remember that a name, or a type, was missing.
$ORIGIN example.com.
$TTL 300
@ IN SOA ns1.example.net. hostmaster.example.com. (
2026110601 ; serial
3600 ; refresh
600 ; retry
604800 ; expire
300 ; negative cache
)
@ IN NS ns1.example.net.
@ IN NS ns2.example.net.
@ IN A 203.0.113.10
@ IN AAAA 2001:db8::10
www IN CNAME example.com.$ORIGIN example.com. adds .example.com to any name with no trailing dot. @ is the apex. hostmaster.example.com. is the mailbox hostmaster@example.com: the first dot stands in for @. ns1.example.net. is outside the zone, so this file needs no glue of its own. Drop the dot on the CNAME target and example.com becomes example.com.example.com.
A, AAAA, and CNAME
An A record is one IPv4 address. An AAAA record is one IPv6 address. A name can have several of each. Clients get the set and choose. Order in the file is not a priority, and a second address is not a health check. A dead address is still tried.
shop IN A 203.0.113.10
shop IN AAAA 2001:db8::10Publish an AAAA record when that IPv6 address answers. Pointed at a closed port, or at an unrouted address, it is what makes Happy Eyeballs wait. Publishing no A record is the other half of the same mistake. An IPv4-only network, still a normal office, build agent, or home router, gets nothing and stops. After a change, query both types.
dig shop.example.com A
dig shop.example.com AAAAA CNAME makes one name an alias of another. It stores no address. The resolver looks up the target, follows a further CNAME up to a small limit, and usually returns the chain plus the final addresses. That is how www tracks the apex, and how a label points at a hostname someone else runs.
www IN CNAME example.com.A CNAME has to be the only record at that name. It cannot sit next to an A, AAAA, MX, or TXT. A panel that saves both has dropped one or is not showing the zone. Query the authoritative server after the save.
The apex cannot be a CNAME. It already has SOA and NS, so example.com. IN CNAME www.example.com. will not load. A provider box labelled CNAME on the root is, when it works, not a CNAME on the wire. The provider resolves the target and answers with A and AAAA. Cloudflare calls that flattening. Route 53 calls it an alias. dig then shows addresses. Paste that into a zone file and the zone fails to load, which looks like SERVFAIL.
Do not point aliases in a circle. NS and MX targets should be names with address records, not CNAMEs. Some resolvers cope with an alias there. Some do not. Give the mail host and the nameserver their own A and AAAA.
TTL and the cache you cannot flush
TTL is seconds. $TTL 300 is a five-minute default for later records. A resolver may cache for that long, or for less, and it will not ask again meanwhile. Nothing pushes an update. resolvectl flush-caches clears one local cache, not the office resolver, the ISP, or a customer's browser.
The wait is the TTL already cached, which is the old one. Lowering TTL in the same edit as the new address does not shorten stored copies. Publish the short TTL, wait out the previous value, then change the address. Raise it again once the name is stable if you do not want the world asking every five minutes. A TTL of 86400 is a full day of serving a mistake you have already fixed in the zone.
Misses are cached too. An NXDOMAIN, or NODATA for a type the name does not have, may be remembered for the SOA negative TTL. Add www a minute after looking it up and it can stay missing until that entry expires.
A cached dig TTL counts down. Twelve means about twelve seconds left in that cache. Read the published value from the authoritative server.
The apex and www
example.com and www.example.com are different names. An address on the apex does not answer for www. The other name needs its own A and AAAA, or a CNAME to a name that has them. The usual partial outage is the name you tested working, and the name on the letterhead not resolving at all. Nothing in the HTTP config runs, because there is no connection to redirect.
A redirect happens after DNS and, for HTTPS, after TLS for the name that was typed. The certificate has to include each of those names. DNS, the certificate, and the redirect are three edits. The redirect is the last.
A wildcard *.example.com matches names that have no records of their own. It does not match the apex, and it does not override a www record that already exists.
Pitfalls
- Caches keep the previous TTL. Compare the authoritative server with the resolver the laptop uses before you edit the zone again.
NXDOMAINand NODATA are cached for the SOA negative TTL. A name you just created can still look missing.- Under
$ORIGIN example.com., a CNAME target without a trailing dot isexample.com.example.com. - A CNAME cannot share its name with other data, and the apex cannot be a CNAME. A provider CNAME on the apex is that provider's alias, not a zone-file line.
- A dead AAAA makes dual-stack clients slow. No A record leaves IPv4-only clients nowhere to connect.
- The apex and
wwware separate. A redirect cannot fix a name that does not resolve, and HTTPS needs the typed name on the certificate. - The registrar NS set is what the world follows. Editing the old DNS host after the delegation moved does nothing. Glue is updated at the registrar as well.
- A secondary whose SOA serial does not increase keeps the old zone.
- The URL path is not a DNS name. A hosts file, or a browser using its own resolver, explains a box that disagrees with
dig.
dig +trace, then the authoritative server, then the resolver in resolv.conf. The file can be right and still not be the answer the browser gets.