How a Request Finds Your Server
The Gap Nobody Thinks About
You type an address, press enter, and a moment later the page is there. That gap is usually about a quarter of a second, and almost nobody thinks about it. Inside it, your computer looked up a name in a worldwide directory that nobody owns, opened a connection to a machine it had never spoken to before, checked that the machine was really who it claimed to be, agreed on a secret code with it, and only then got around to asking for the page.
This lesson is about that gap. Everything in it happens before HTTP - the language browsers and servers actually talk in - says a single word. If you have read the lesson on how HTTP works, this one sits underneath it: HTTP is the conversation, and this is everything that has to happen before the two parties can hear each other at all.
It is worth knowing for ordinary, practical reasons. When a site feels slow, the cause is very often somewhere in this gap rather than in any code you wrote. When you change where a domain points and half the world keeps seeing the old server for the rest of the day, the reason is in here. When someone asks why the database cannot be reached from the internet, the answer is in here too.
Those first three bars are the subject of this lesson. Notice how much of the total they account for: more than half the time, and not one millisecond of it was spent running your code or reading your database. On a first visit from a phone on a mobile network, that setup cost can easily be two or three times larger than what is drawn here.
Turning a Name Into a Number
Networks do not route traffic to names. A name like dawn.mk means nothing to any of the equipment between you and the server; what that equipment needs is an address, a number such as 203.0.113.10. The system that turns one into the other is DNS, the Domain Name System, and it is usually described as the internet's phone book. That comparison is where most explanations stop, and it is slightly misleading, because the interesting thing about DNS is that there is no phone book. No machine anywhere holds a list of every domain name in the world.
The answer gets assembled instead out of a chain of referrals. Your computer asks one server, that server asks another, and each one along the way knows a little more than the last, until something finally knows the real answer. Nobody in the chain knows the whole thing.
The four players are worth naming properly, because you will meet all of them again. The recursive resolver is the one doing the legwork on your behalf, usually run by your internet provider, though 1.1.1.1 and 8.8.8.8 are public ones you can point your machine at instead. The root servers sit at the top of the hierarchy and know only one thing: which servers are responsible for each ending, like .com or .mk. The TLD servers for that ending know which name servers a particular domain has nominated. And the authoritative server is the one that actually holds the records for that domain - it is the only one in the chain giving you a real answer rather than a referral.
You can watch this happen yourself. The `dig` command asks a resolver a question and prints back exactly what it got, and the `+trace` option makes it walk the chain manually rather than accepting a cached answer, so you can see every referral.
$ dig dawn.mk
;; QUESTION SECTION:
;dawn.mk. IN A
;; ANSWER SECTION:
dawn.mk. 300 IN A 203.0.113.10
# ^^^ ^ ^^^^^^^^^^^^
# | | the address you actually needed
# | the record type: A means "IPv4 address"
# the TTL, in seconds - how long this answer may be cached
;; Query time: 28 msec
# Walk the whole chain instead of taking a cached answer:
$ dig dawn.mk +trace
. 518400 IN NS a.root-servers.net. # step 2: the root
mk. 172800 IN NS ns1.marnet.mk. # step 3: the .mk servers
dawn.mk. 86400 IN NS ns1.dawn.mk. # step 4: who really knows
dawn.mk. 300 IN A 203.0.113.10 # the answer, at lastThe number in the middle of that answer line - 300 - is the one that catches people out, and it deserves its own section.
Why a DNS Change Takes Hours
That number is the TTL, or time to live, measured in seconds. It is not how long the record is valid. It is permission: it tells every resolver that hears this answer how long it may keep reusing it without asking again. A TTL of 300 means five minutes. A TTL of 86400, which is extremely common, means a full day.
This is why moving a site to a new server feels so strange the first time you do it. You change the record to point at the new address, you check it yourself, and it works immediately. Meanwhile a colleague in another city keeps landing on the old server, and keeps landing there for hours, and there is nothing you can do about it. Their resolver cached the old answer twenty minutes before you made the change, and it is entitled to keep using that answer until its TTL runs out. Nobody did anything wrong. The system is behaving exactly as designed.
The fix has to happen before the move, not after. Drop the TTL to something small like 300 seconds at least a full old-TTL period ahead of the migration - if the record is on 86400, that means a day in advance. Then everyone's cached copy expires quickly during the switch, and you can put the TTL back up afterwards. Lowering it on the day of the move does nothing for anyone who already cached the old value.
Opening the Connection
Now your browser has an address. It still cannot send anything useful, because the underlying protocol, TCP, insists on setting up a connection first. TCP is what guarantees that the bytes you send arrive, in order, without duplicates - and to make those promises it needs both sides to agree they are talking before any real data moves.
That agreement is three short messages, and it is genuinely just the network version of checking a phone line: one side says can you hear me, the other says yes and can you hear me, the first says yes. Only then does anyone start talking.
Browser Server
| |
| ------------ SYN ----------------------------> | "I would like to talk."
| |
| <----------- SYN-ACK ------------------------- | "Heard you. I would too."
| |
| ------------ ACK ----------------------------> | "Heard you. Starting now."
| |
| ============ connection is open ============== |Each of those arrows is a real trip across a real distance, and this is where physics starts charging you rent. Light in fibre travels at roughly 200,000 kilometres per second, which is fast but not instant. Frankfurt to Sydney is about 16,000 kilometres of cable, so one crossing takes around 80 milliseconds at the absolute theoretical best, and a there-and-back is 160. No amount of money buys a faster server that gets around this. It is the reason distance to your users is a real engineering decision rather than a detail.
Proving the Server Is Who It Claims
The connection is open, but it is wide open - anyone sitting between you and the server, on the coffee shop wifi or at the internet provider, could read every byte. TLS is the layer that fixes this, and it is what the s in https stands for. It does two separate jobs that are worth keeping apart in your head: it encrypts the traffic so nobody in the middle can read it, and it checks that the server on the other end is genuinely the one that owns the domain you asked for.
That second job is the one people misunderstand. The server presents a certificate, which is essentially a signed statement from a certificate authority saying yes, whoever holds this really does control dawn.mk. Your browser ships with a list of authorities it trusts, so it can check that signature without asking anyone. You can look at the whole exchange yourself:
$ openssl s_client -connect dawn.mk:443 -servername dawn.mk
Certificate chain
0 s:CN = dawn.mk # the site's own certificate
i:C = US, O = Let's Encrypt, CN = R11 # signed by this authority
1 s:C = US, O = Let's Encrypt, CN = R11 # that authority's certificate
i:C = US, O = ISRG, CN = ISRG Root X1 # signed by this root
# Your browser already trusts ISRG Root X1, because it shipped with it.
# Trust flows down that chain: root -> intermediate -> this site.
SSL handshake has read 4096 bytes and written 396 bytes
Verify return code: 0 (ok)The padlock in the address bar means the connection is private and the certificate matches the domain. It does not mean the site is honest, safe, or run by anyone reputable. Certificates are free and take about a minute to obtain, so a phishing site imitating your bank will show a perfectly valid padlock. The padlock tells you nobody is eavesdropping. It says nothing at all about who you are talking to.
TLS used to cost two full round trips on top of the TCP handshake, which is why older sites sometimes felt sluggish on https specifically. TLS 1.3, which almost everything uses now, cut that to one, and for a server you have visited recently it can resume a previous session and cost effectively nothing. This is one of the few areas of networking where things genuinely got faster over the last decade.
Putting Real Numbers On It
None of this has to stay theoretical. `curl` can report exactly how long each phase took on a real request, which turns an argument about why the site feels slow into a measurement.
$ curl -w "\
dns: %{time_namelookup}s\n\
tcp: %{time_connect}s\n\
tls: %{time_appconnect}s\n\
first byte: %{time_starttransfer}s\n\
total: %{time_total}s\n" \
-o /dev/null -s https://dawn.mk
dns: 0.031s # finding the address
tcp: 0.072s # connection open (41 ms more)
tls: 0.134s # encryption agreed (62 ms more)
first byte: 0.213s # server finished thinking (79 ms more)
total: 0.251s # page fully downloaded (38 ms more)These numbers are cumulative, not individual, which is the one trick to reading them: each is the time since the request started. To get the cost of a single phase you subtract the one above it. Run this against a slow page and the phase that jumped will tell you where to look - and it is surprisingly often not the one you assumed.
What Sits In Front of the Server
In anything beyond a hobby project, the machine that answers is not the machine that runs your code. Two things usually sit in front of it. A load balancer accepts every incoming connection and spreads the work over several identical servers behind it, which is both how a site survives one machine dying and how it handles more traffic than one machine can. You will see them described as layer 4 or layer 7: a layer 4 balancer just forwards the connection without looking inside it, which is fast and dumb; a layer 7 one reads the actual HTTP request and can make decisions on it, sending /api to one group of servers and everything else to another.
A CDN sits further out still, with copies of your static files in dozens of cities, so a visitor in Singapore is served from Singapore instead of from Frankfurt. The obvious benefit is that cached files arrive faster. The less obvious one matters more: the TCP and TLS handshakes now happen against a machine 10 milliseconds away rather than 150 milliseconds away. Look back at the first diagram and imagine the first three bars shrinking by 80 percent. That is why a CDN speeds up even pages it cannot cache at all.
Where the Server Actually Lives
One last piece, because everything in the next two lessons builds directly on it. Your server does not sit nakedly on the internet. It sits inside a private network you define, and the addresses inside it - the ones starting 10., or 192.168. - are not reachable from the outside world at all. Those ranges are reserved for private use, and every home router in the world uses the same ones, which is why your laptop and mine can both be 192.168.1.5 without anything catching fire.
That private network gets carved into subnets, and the notation looks worse than it is. 10.0.0.0/16 means the first 16 bits of the address are fixed and the rest are yours to allocate, giving you everything from 10.0.0.0 to 10.0.255.255. Carve a /24 out of it, like 10.0.1.0/24, and the first 24 bits are fixed, leaving you 10.0.1.0 to 10.0.1.255. Bigger number, smaller range. That is the entire trick.
The split in that diagram is the standard arrangement, and the reasoning behind it is worth stating plainly. Things that must be reachable from the internet go in the public subnet, and there should be as few of them as possible - usually just the load balancer. Everything else goes in the private subnet, where there is simply no route in from outside. Not a firewall rule that could be misconfigured, not a password that could leak: no path exists.
The application server still needs to reach out, though, to install updates or call somebody's API. That is what the NAT gateway does: it lets connections out and lets the replies back in, while refusing to let anyone outside start a conversation. Outbound yes, inbound no. It is the same arrangement your home router has been quietly running for you this whole time.
What This Buys You
You can now answer questions that used to be mysteries. Why does the site feel slow for users in another country, when the server is not busy at all? Distance, and the handshakes that have to cross it. Why did the deploy work for you and not for your colleague? DNS caching, and a TTL that had not expired yet. Why can the application server reach the database when your laptop cannot? Because one of them is inside the private network and the other is not, which is the arrangement working correctly rather than a bug.
The single most useful habit from this lesson is measuring instead of guessing. The next time something feels slow, run the `curl` timing command against it before forming a theory. Most people, most of the time, guess wrong about which phase is the expensive one - and the measurement takes about four seconds.
Further reading
- How DNS Works, by CloudflareA clear walkthrough of the resolution chain covered above, with more detail on record types than this lesson goes into.
- RFC 9293: Transmission Control ProtocolThe current TCP specification. Dense, but section 3.5 is the actual definition of the three-way handshake drawn above.
- RFC 8446: TLS 1.3The specification behind the round-trip reduction described in the TLS section.
- Let's Encrypt: How It WorksHow free certificates are issued and validated - useful context for why the padlock proves less than people assume.
- High Performance Browser NetworkingIlya Grigorik's book, free to read online. Chapters 1 to 4 cover this lesson's ground in considerably more depth.
- curl's --write-out documentationEvery timing variable available to the measurement command used above, not just the five shown here.