Skip to content

What happens when you open a website

The browser turns a name into an IP address (DNS), opens a secure connection to it (TCP plus TLS, or QUIC), sends an HTTP request, and renders the response while fetching everything the page refers to.

Each layer fixed a specific problem of the one before it.

  • IP (1981) moves packets between machines but promises nothing: packets can be lost, duplicated or reordered.
  • TCP (1981) adds a reliable ordered byte stream on top of IP.
  • DNS (1983) replaced a single HOSTS.TXT file that every machine had to download, so people could use names instead of addresses.
  • HTTP (1991) gave a document format a way to be requested by name.
  • TLS (SSL in 1995, TLS 1.3 in 2018) added encryption and proof of who the server is, because the layers below are readable and forgeable by anyone on the path.
  • QUIC and HTTP/3 (2021 and 2022) moved transport into user space over UDP to remove delays that TCP cannot fix.

Example: you type https://example.com/ and press Enter.

  1. URL parsing. The browser splits the URL into scheme (https), host (example.com), port (443 by default for https) and path (/). If the text is not a URL, it becomes a search query.
  2. HSTS check. If the host is on the HTTP Strict Transport Security list (preloaded in the browser, or remembered from an earlier Strict-Transport-Security header), the browser uses HTTPS without ever trying HTTP.
  3. Cache check. A fresh cached response (Cache-Control: max-age) is used without any network at all. A stale one is revalidated later with If-None-Match.
  4. DNS lookup. The browser checks its own cache, then the OS cache and /etc/hosts, then asks the configured recursive resolver. On a cold cache the resolver walks the tree: a root server, the .com servers, then the authoritative server for example.com. The answer is an A record (IPv4) or AAAA record (IPv6) with a TTL. Modern browsers also ask for the HTTPS record, which can say “this site supports HTTP/3”. See DNS.
  5. Connection. With both IPv4 and IPv6 answers the browser races them (Happy Eyeballs) and keeps the first that connects.
    • TCP: the three-way handshake, SYN, SYN-ACK, ACK. One round trip.
    • QUIC: if the browser knows the site speaks HTTP/3, it sends a UDP packet to port 443 that carries the transport and TLS handshakes together.
  6. TLS handshake. In TLS 1.3 this takes one round trip. The client sends ClientHello with the server name (SNI), the protocols it speaks (ALPN: h2, http/1.1) and a key share. The server answers with its key share, its certificate and a signature. The browser checks the certificate chain up to a root it trusts, the name, the dates and the signature. Both sides now have the same session keys. See TLS.
  7. HTTP request. The browser sends GET / with headers such as Host, User-Agent, Accept-Encoding and Cookie. On HTTP/2 and HTTP/3 this is a binary frame on a stream, and many requests share one connection. See HTTP versions.
  8. The server side. The IP usually belongs to a CDN or a load balancer, not the application. A typical chain is CDN edge, load balancer, reverse proxy or ingress, application, database. TLS is often terminated at the edge and started again towards the origin.
  9. HTTP response. A status code (200, 301, 404, 503), headers (Content-Type, Cache-Control, Set-Cookie, Content-Encoding: br) and the body.
  10. Rendering. The browser parses HTML into the DOM and CSS into the CSSOM, combines them into a render tree, computes layout, paints and composites. CSS blocks rendering. A plain <script> blocks parsing until it has downloaded and run; defer and async avoid that.
  11. Subresources. Every stylesheet, script, image and font repeats steps 3 to 9, mostly over the connection that is already open. Other origins need their own DNS lookup and connection.
Browser DNS resolver Server (CDN edge) DNS example.com A, AAAA, HTTPS ? 93.184.x.x, TTL 300 TCP SYN SYN-ACK ACK TLS 1.3 ClientHello: SNI, ALPN, key share ServerHello, certificate, Finished Finished HTTP GET / (encrypted) 200 OK, HTML (encrypted) parse, fetch subresources, render
A cold load over TCP costs one DNS round trip, one for TCP and one for TLS 1.3 before the first request. Green arrows are encrypted or part of the TLS handshake. In practice the client sends the request together with its Finished message.

How many round trips before the first byte of the request

Section titled “How many round trips before the first byte of the request”
Setup Round trips before the request Notes
TCP + TLS 1.2 3 1 TCP, 2 TLS
TCP + TLS 1.3 2 1 TCP, 1 TLS
QUIC (HTTP/3), first visit 1 transport and TLS handshake combined
TLS 1.3 or QUIC resumption with 0-RTT 0 extra for the request early data can be replayed, so only safe for idempotent requests

DNS adds its own round trip on a cold cache, in every row.

Where time goes, and what fixes it.

Stage Typical cost What reduces it
DNS 1 to 100+ ms cold, 0 cached longer TTLs, a nearby resolver, dns-prefetch
TCP handshake 1 round trip keep-alive, connection reuse, HTTP/3
TLS handshake 1 round trip (1.3) session resumption, 0-RTT, TLS termination close to the user
Request and server time application-dependent caching, CDN, faster back end
Download size divided by bandwidth compression (Brotli, zstd), smaller assets, CDN
Render CPU-dependent less blocking CSS and JavaScript, defer, lazy loading

Who answers on port 443, from the outside in.

Hop Job Examples
CDN edge cache, TLS termination, DDoS and WAF filtering Cloudflare, CloudFront, Fastly
Load balancer spread connections across healthy targets AWS ALB and NLB, Google Cloud Load Balancing, HAProxy
Reverse proxy or ingress routing by host and path, retries, rate limits nginx, Envoy, Traefik, Kubernetes Ingress or Gateway
Application business logic your service
Data stores state PostgreSQL, Redis, object storage

Work from the bottom layer up. Each command answers one question.

Symptom Likely layer Check
DNS_PROBE_FINISHED_NXDOMAIN, “could not resolve host” DNS dig +short example.com, dig @1.1.1.1 example.com, dig +trace example.com
Hangs, then “connection timed out” network or firewall drops packets nc -vz example.com 443, mtr example.com, security groups
“Connection refused” straight away nothing listens on that port ss -ltnp on the server, target health on the load balancer
Certificate error TLS: expired, wrong name, missing intermediate openssl s_client -connect example.com:443 -servername example.com
502 Bad Gateway the proxy reached the back end and got a bad or no answer proxy logs, back end crashed or closed the connection
503 Service Unavailable no healthy back end health checks, pod readiness
504 Gateway Timeout the back end did not answer in time back end latency, proxy timeout settings
Slow first load only cold DNS, cold connection, cold cache timing breakdown below

One command that times every stage:

Terminal window
curl -s -o /dev/null -w 'dns %{time_namelookup}\ntcp %{time_connect}\ntls %{time_appconnect}\nttfb %{time_starttransfer}\ntotal %{time_total}\n' https://example.com/

Each value is cumulative seconds from the start, so the TLS handshake took time_appconnect - time_connect.

See which HTTP version was negotiated and all response headers:

Terminal window
curl -sI --http3 https://example.com/ # needs a curl built with HTTP/3
curl -sIv https://example.com/ 2>&1 | grep -E 'ALPN|HTTP/'

URL, HSTS, HSTS preload, DNS, recursive resolver, authoritative server, A record, AAAA record, HTTPS record, TTL, Happy Eyeballs, TCP three-way handshake, SYN, ACK, QUIC, UDP 443, TLS 1.3, ClientHello, SNI, ALPN, certificate chain, session resumption, 0-RTT, HTTP/2, HTTP/3, CDN, load balancer, reverse proxy, TLS termination, status code, Cache-Control, DOM, CSSOM, render-blocking, TTFB, round trip time (RTT).