Day 1 — Client-Server, HTTP/HTTPS, and DNS
Goal: Own the plumbing that underlies every system design. By the end of this lesson you should be able to:
- Explain the client-server model precisely
- State (and defend) that HTTP is stateless — and how apps add state on top
- Walk through what happens end-to-end when a user hits www.example.com
- Choose the right HTTP status codes and methods in a design
- Understand HTTPS at a mental-model level (TLS handshake gist)
Estimated time: 50–60 min read + reflection.
1. The Client-Server model
A client initiates requests. A server listens for requests and responds. That's it, conceptually.
Client --- request ---> Server
Client <-- response --- Server
- Client examples: browser, mobile app, curl, another backend service, IoT device.
- Server examples: web server (nginx), API server (Node/Django/Go), database, cache, CDN edge.
Key properties: - Asymmetric roles — clients know where the server is; the server doesn't need to know all clients up front. - Request-response is the default pattern (HTTP). For push, we use WebSockets, SSE, or long polling (Day 3). - Servers are typically shared — one server handles many concurrent clients.
Why this matters for design: every box you draw in a system-design diagram is either a client, a server, or both. Almost every "service" is a server for someone and a client for something else (an API server is a client of the database).
2. HTTP — the request/response protocol
HTTP (HyperText Transfer Protocol) is a text-based, stateless, request-response protocol built on top of TCP.
2.1 Anatomy of an HTTP request
POST /api/v1/orders HTTP/1.1 <-- request line: METHOD PATH VERSION
Host: api.example.com <-- headers (metadata: key: value)
Content-Type: application/json
Authorization: Bearer eyJhbGc...
Content-Length: 58
{"item_id": "abc123", "quantity": 2} <-- body (optional)
2.2 Anatomy of an HTTP response
HTTP/1.1 201 Created <-- status line: VERSION STATUS_CODE REASON
Content-Type: application/json
Location: /api/v1/orders/999
Content-Length: 42
{"order_id": 999, "status": "confirmed"}
2.3 HTTP methods (must know cold)
| Method | Purpose | Safe? | Idempotent? |
|---|---|---|---|
| GET | Retrieve a resource | Yes | Yes |
| POST | Create / non-idempotent action | No | No |
| PUT | Replace a resource entirely | No | Yes |
| PATCH | Partially update a resource | No | Usually |
| DELETE | Remove a resource | No | Yes |
| HEAD | Like GET but no response body | Yes | Yes |
| OPTIONS | Check allowed methods (CORS etc.) | Yes | Yes |
- Safe = doesn't modify server state.
- Idempotent = calling N times has the same effect as calling once. Crucial for retries.
2.4 HTTP status codes (know these ranges + the top ones)
| Range | Meaning | Examples you must know |
|---|---|---|
| 1xx | Informational | 101 Switching Protocols (WebSocket upgrade) |
| 2xx | Success | 200 OK, 201 Created, 204 No Content |
| 3xx | Redirection | 301 Moved Permanently, 302 Found, 304 Not Modified |
| 4xx | Client error | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404, 409 Conflict, 429 Too Many Requests |
| 5xx | Server error | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout |
Fast rules of thumb: - 401 vs 403 — 401 = "I don't know who you are." 403 = "I know who you are and you can't do this." - 502 vs 503 vs 504 — 502 = bad response from upstream. 503 = we're down/overloaded. 504 = upstream timed out.
3. HTTP is stateless — this is huge
The server does NOT automatically remember anything about a client between requests.
Each HTTP request is a self-contained transaction. The server processes it and forgets it happened. Two consecutive requests from the same client look identical to two requests from two different clients — unless the client explicitly re-supplies identifying information (cookie, token, session ID) on every request.
3.1 Why did the designers do this?
- Simplicity — servers don't need per-client memory management, cleanup, or reconciliation.
- Scale — any server can serve any request → trivial horizontal scaling behind a load balancer. This is the reason web scaled.
- Reliability — if a server crashes, no client "session" is lost on that box.
3.2 But apps clearly "remember" me — how?
State is added on top of HTTP, on every request:
| Mechanism | How it works |
|---|---|
| Cookies | Server sends Set-Cookie: sid=abc. Browser echoes Cookie: sid=abc on every subsequent request. |
| Server sessions | The cookie is an opaque ID. Server looks up state (user_id, cart, etc.) in a session store (Redis, DB). |
| JWT / Bearer | Signed token in Authorization: Bearer <token> header. Self-contained: no server-side lookup. |
| URL parameters | ?session=abc — visible, leaks in logs, mostly deprecated for auth. |
3.3 The system-design implication (memorize this)
Because HTTP is stateless: - Any app server can serve any request → put N app servers behind a load balancer, round-robin traffic. - You must externalize session state — put it in Redis / Memcached / DB, not in-process memory. Otherwise, sticky sessions become required and horizontal scaling gets painful. - Failures are cheap — kill an app server, another one picks up the next request. No warm-up per user.
This is why the diagnostic Q5 answer is False. If a FAANG interviewer hears "HTTP is stateful," it's an immediate red flag.
4. HTTP versions — what to know
| Version | Year | Key changes |
|---|---|---|
| HTTP/1.0 | 1996 | One request per TCP connection (slow: TCP handshake per request) |
| HTTP/1.1 | 1997 | Persistent connections (keep-alive), pipelining, Host header (virtual hosts) |
| HTTP/2 | 2015 | Binary framing, multiplexing many requests on one TCP connection, header compression (HPACK), server push |
| HTTP/3 | 2020+ | Runs over QUIC (UDP-based), solves TCP head-of-line blocking, faster handshake |
Interview-relevant facts: - HTTP/1.1 → HTTP/2: massive win for pages with many small assets, because multiplexing removes the browser's 6-connection-per-domain limit. - HTTP/3 shines on lossy networks (mobile) — QUIC recovers from packet loss without stalling all streams.
5. HTTPS = HTTP over TLS
- HTTPS = HTTP transported over a TLS-encrypted TCP connection.
- Protects: confidentiality (nobody can read), integrity (nobody can tamper), authenticity (you're really talking to
example.com).
5.1 TLS handshake (simplified, conceptual)
- Client Hello — client sends supported TLS versions and cipher suites.
- Server Hello + Certificate — server picks a cipher, sends its X.509 certificate (contains public key, signed by a CA).
- Client verifies certificate — checks CA chain, expiration, hostname match.
- Key exchange — via Diffie-Hellman (ephemeral, for forward secrecy), both sides derive a shared symmetric key.
- Encrypted app data flows over the connection using the symmetric key (fast).
Cost you should know: - TLS 1.2: 2 round trips to establish (on top of the TCP 1 RTT). So an HTTPS connection to a fresh host = ~3 RTTs before any data. - TLS 1.3: 1 round trip (or 0-RTT for resumption). - On a cross-continent link (~150 ms RTT), that's a noticeable startup cost. This is why keep-alive, HTTP/2 multiplexing, and edge servers (CDNs) matter so much.
6. DNS — the name-to-address system
DNS (Domain Name System) translates human-friendly names (www.example.com) into IP addresses (93.184.216.34 or 2606:2800:...).
6.1 The hierarchy
. (root)
/|\
.com .org .net .in ... <-- TLD nameservers
/
example.com <-- authoritative NS for example.com
/
www.example.com <-- an A record inside example.com's zone
6.2 Full lookup for www.example.com
[Browser cache] --miss--> [OS cache] --miss--> [Recursive resolver (ISP / 8.8.8.8)]
|
v
asks Root NS: "who runs .com?"
(root replies: gtld-servers)
|
v
asks .com TLD NS: "who runs example.com?"
(TLD replies: ns1.example.com, etc.)
|
v
asks example.com's authoritative NS:
"what's the A record for www?"
(replies: 93.184.216.34)
|
v
Resolver returns IP -> OS -> Browser
Browser opens TCP to 93.184.216.34
Important nuances: - Caching at every layer with TTLs. Most lookups never hit the root — they're resolved from a cache. - The recursive resolver does the walking; the client just asks once. - Authoritative nameservers are the source of truth for a zone; you configure them via your DNS provider (Route53, Cloudflare DNS, etc.).
6.3 Common record types
| Record | Purpose |
|---|---|
| A | Name → IPv4 address |
| AAAA | Name → IPv6 address |
| CNAME | Alias one name to another name |
| MX | Mail server for the domain |
| TXT | Arbitrary text (SPF, DKIM, domain verification) |
| NS | Which nameservers are authoritative |
6.4 DNS as a system-design tool
- Global load balancing — return different A records per region (geo-DNS), or per weight, or based on health checks.
- Failover — health-checked DNS (Route53 health checks) drops unhealthy IPs.
- Multi-CDN routing — split traffic across CDNs.
- Cost: DNS lookup adds ~20–100 ms cold, near 0 warm.
- Downside: TTLs mean changes propagate slowly. Emergency failover via DNS is slow (minutes).
7. Full end-to-end: what happens when you hit www.example.com
Combining everything:
- Browser cache check — is
www.example.com's IP cached and not expired? If yes → skip to step 6. - DNS lookup — browser → OS → recursive resolver → root → .com TLD → example.com NS → IP.
- TCP handshake — SYN → SYN-ACK → ACK (1 RTT).
- TLS handshake — Client Hello, Server Hello + cert, key exchange (1–2 RTTs).
- HTTP request sent —
GET / HTTP/1.1\r\nHost: www.example.com\r\n... - Server responds — often the request first hits a CDN edge (which either serves cached content, or forwards to origin), then a load balancer, then an app server, which may talk to caches and databases to build the response.
- Browser parses HTML → discovers linked assets (CSS/JS/images) → fetches them (multiplexed over HTTP/2 or new connections for HTTP/1.1).
- Render.
This 8-step flow is a mental map you can lay on top of any system-design diagram. When someone asks "where would you add caching?" — the answer is usually "at as many of these steps as possible" (browser cache, CDN, app cache, DB cache).
8. Interview angle (what FAANG actually asks)
Common openings from real interviews: - "Walk me through what happens when a user types a URL and hits enter." → your Section 7 answer. - "Why is HTTP stateless? What's the design implication?" → Section 3.3 — talk about horizontal scaling. - "When would you use POST vs PUT? Why does idempotency matter?" → PUT for replace, POST for create/non-idempotent. Idempotency matters for retries (client retries a lost response — with PUT it's safe; with POST you risk duplicate creation unless you add an idempotency key). - "Difference between 401 and 403?" — auth vs authorization. - "How does HTTPS work at a high level? What's the cost?" → TLS 1–2 RTT overhead, symmetric encryption after handshake. - "How would you use DNS to do global load balancing?" → geo-DNS, weighted records, health checks; caveat: TTL slowness.
Trap they set: they'll say "your service is slow for users in Australia." A weak candidate says "add servers in Australia." A strong candidate says: "First measure — where's the latency? DNS? TLS? App? DB? Each of the 8 steps above is a possible hotspot. The remediation depends on which one is slow."
9. Quick reference card (memorize)
- HTTP is stateless. State is added via cookies / sessions / tokens.
- PUT and DELETE are idempotent; POST is not.
- 401 = who are you? / 403 = you can't. / 404 = not there. / 409 = conflict. / 429 = too many. / 5xx = server's fault.
- HTTPS = HTTP + TLS. TLS 1.3 handshake = 1 RTT.
- DNS lookup path: browser cache → OS → recursive resolver → root → TLD → authoritative NS.
- DNS TTLs mean DNS-based failover is slow (minutes).
- HTTP/2 multiplexes many requests on one TCP connection. HTTP/3 runs over QUIC (UDP).
Ready for the Day 1 quiz? It's saved at quizzes/day-01-client-server-http-dns-quiz.md. Answer in chat.