Skip to content
Episode 49 · Your connection is not private

HTTP and TLS: the language of the web, encrypted

Saturday, 00:00 UTC: every browser starts refusing api.stayhub.com with "Your connection is not private", and bookings drop from 200 an hour to zero. Nothing was deployed. Nothing crashed.

What your browser and your server actually say to each other, and how the padlock keeps strangers out of the conversation.

30 min intermediateHTTP/1.1 vs HTTP/2 vs HTTP/3HTTP caching headers (Cache-Control, ETag)Keep-alive & connection reuseTLS handshake & certificate chainsHTTP methods & status codesHead-of-line blocking
  1. Problem

    A hotel search page needs 80 resources from a server 100 ms away, privately, without anyone on the café Wi-Fi reading card numbers or swapping prices.

  2. Why the simple system fails

    Plain HTTP/1.1 sends readable text, handles one request at a time per connection, and a fresh connection per request spends most of the time on handshakes instead of data.

  3. Engineering concept

    Reuse connections, multiplex many requests over them, let caches skip requests entirely, and wrap everything in TLS so the server proves its identity and traffic is encrypted.

  4. Technology

    HTTP/1.1, HTTP/2, HTTP/3 over QUIC, Cache-Control and ETag, keep-alive, TLS 1.3, X.509 certificates and certificate authorities.

  5. Trade-offs

    Every round trip saved adds complexity (multiplexing, UDP-based transport, cache invalidation). TLS costs a round trip and certificate operations; skipping it is never acceptable on the public internet.

01

The problem

2 min
Saturday, 00:04 UTC. Omar's phone wakes up the team.
  1. Omar · On-call SRE
    100% of API calls failing since 00:00:00. Browsers: "Your connection is not private". Bookings 200/hour → 0.
  2. Karim · CTO
    Who deployed on a Friday night?
  3. Omar · On-call SRE
    Nobody. Servers healthy, CPU 12%.
02

The big idea

4 min
Midnight, and every browser says no
The big idea

Every certificate has an expiry date. Renew automatically, and watch every one.

The certificate was bought by hand and renewed once by an engineer who has since left. The fix took until 01:50, because someone had to find the CA login: about 370 bookings lost. The CDN's certificates renew themselves; they were fine.

03

How it works

5 min
What happens before a single byte of HTTP
  1. 1
    HTTP inside TLS

    is the web's request/response language: method, path, headers, a status code. encrypts the connection and proves the server's identity. Together: HTTPS.

  2. 2
    Client hello

    In the , the browser sends the name it wants (: api.stayhub.com), the protocols it speaks (h2, h3) and a key share.

  3. 3
    The server shows its ID

    A is the server's ID card: name, public key, validity dates, and a signature from a certificate authority (CA) your device already trusts. The server sends it plus the intermediate that signed it.

  4. 4
    The browser checks, locally

    Name matches? Dates valid? Chain of signatures leads to a trusted root? No call to the CA, no grace period. Any check fails: it hangs up.

  5. 5
    Encrypted HTTP

    Both sides derive the same keys; the request goes out encrypted. TLS 1.3 adds one round trip on top of TCP's.

  6. 6
    Headers decide who keeps a copy

    Cache-Control says who may store a response: hashed files a year, hotel data max-age=60 with an (unchanged → a tiny 304), anything personal private, no-store.

04

Watch a decision being made

4 min
Worked example

Lina makes sure it never happens again

A hand-bought certificate cost 1 h 50 min of downtime. Make every certificate renew itself, and know weeks before any could expire.

  1. 1Find every certificate

    List every hostname and port serving TLS, public and internal, and read each end date.

    bash
    openssl s_client -connect api.stayhub.com:443 -servername api.stayhub.com </dev/null \
      | openssl x509 -noout -subject -issuer -enddate

    Why: You can't renew what you don't know exists. Internal certificates are the forgotten ones.

  2. 2Check the whole chain

    With -showcerts, confirm each server sends its certificate and the intermediate.

    Why: Browsers fill in a missing intermediate; servers and phones often don't.

  3. 3Automate renewal

    ACME on the load balancer, CDN-managed certificates elsewhere, renewing at two-thirds of the lifetime.

    Why: A bot that renews daily can't be forgotten when someone leaves.

  4. 4Alert on days left

    A daily external check alerts at 30, 14 and 7 days; at 7 it pages on-call. Prove it in staging with a 2-day certificate.

    Why: Automation fails silently too (expired DNS token, firewall change). Watch the outcome, not the process.

The whole thing in one line: Expiry became a routine, watched event: every certificate known, chains complete, renewal by a bot, alerts weeks ahead.
05

In real life

3 min
Automated short-lived versus bought by hand

Let's Encrypt: 90 days, automated

  • Publicly offers free 90-day certificates through the ACME protocol
  • The short lifetime is meant to push everyone to automate
  • A renewal bot runs daily; humans never touch it

Fits any service where a bot can prove control of the domain.

A paid certificate, installed by hand

  • Commercial CAs sell certificates valid up to about a year, the maximum browsers accept
  • Bought on a card, installed manually
  • Renewal depends on a calendar reminder and a login

Fits rare cases needing a specific CA, and only with monitoring.

06

What goes wrong

3 min
Disabling verification to "fix" an error

It accepts any impostor, often for every call in the process.

Instead

Fix the chain; trust a specific intermediate only for the client that needs it.

Renewing certificates by hand

Someone forgets or leaves; at expiry every client fails at once.

Instead

ACME automation, an inventory, alerts well before expiry.

Caching personal responses with `public`

A CDN serves the first guest's bookings to everyone.

Instead

Default per-user responses to private, no-store.

07

Trade-offs

3 min
OptionFits whenYou pay
TLS ends at the load balancerSmall systems, a temporary stageInternal traffic readable by anyone inside
Re-encrypt to every service (TLS or mTLS)Payments, personal data, complianceMany certificates to automate; harder debugging
Monday, 11:00. The postmortem.
  1. Lina · Senior engineer, your mentor
    Next: encrypt inside too. Today it's plain HTTP behind the load balancer.
  2. Karim · CTO
    We just lost two hours to one certificate. You want a hundred more?
  3. Lina · Senior engineer, your mentor
    Our network is private until one machine inside is compromised. Then every token between services is readable.
08

Your job as tech lead

4 min

Claude Code can write the code for this. You still own the decisions, and you have to know what good looks like to accept or reject its work.

Decisions you own
  • The Cache-Control rule per kind of response. Claude copies whatever header the nearest file uses.
  • That certificate verification is never turned off, anywhere. Broken chains get fixed.
  • How certificates renew and when you're warned: 30, 14 and 7 days, paging at 7, public and internal.
Tell Claude Code
api.stayhub.com was down 1 h 50 min because a hand-bought certificate expired; about 370 bookings lost. Don't change production yet. List every hostname and port in our infrastructure config that serves TLS, public and internal, with the command to read its expiry and check the full chain. Then propose ACME renewal on the load balancer at two-thirds of the lifetime and a daily check alerting at 30, 14 and 7 days. Never disable verification. Include a staging test with a 2-day certificate.
Check before you accept
  • Compare Claude's hostname list with what you know exists. A missing one is a future outage.
  • Search the diff for NODE_TLS_REJECT_UNAUTHORIZED and rejectUnauthorized: false: zero hits.
  • Block renewal in staging and see the alert fire.
Red flags
  • It "fixes" a chain error by disabling verification.
  • It adds Cache-Control: public to a response that depends on who is logged in.
  • It skips the expiry alert because "renewal is automated".
09

Check yourself

2 min
Q1/3Reasoning
During every TLS handshake, the browser contacts the certificate authority to ask whether the server's certificate is valid.
How confident are you?

Next episode: StayHub moves its API to a new load balancer, changes one DNS record, and hours later some guests still land on the old one.

Finished?

Mark it complete to update your skill map.

Go deeper (optional)You don't need this to understand the lesson. Open it when a project needs the details: Technical deep dive, Interactive simulation, Visual diagram, Analogy, Check your understanding, Practice ladder, Explain it yourself.
10

Technical deep dive

Headers decide who keeps a copy
Worked example

Lina makes sure it never happens again

api.stayhub.com went down for 1 h 50 min because a hand-bought certificate expired. Make every StayHub certificate renew itself, and make sure we'd know weeks before any of them could expire.

  1. 1Find every certificate

    List every hostname and port that serves TLS, public and internal: api, www, partners, the admin panel, service-to-service endpoints. For each, read the end date with openssl s_client … | openssl x509 -noout -enddate.

    Why: You can't renew what you don't know exists. Internal certificates are the ones most often forgotten.

  2. 2Check the whole chain

    Run openssl s_client -showcerts and confirm each server sends its certificate and the intermediate. Fix any that send only their own.

    Why: Browsers often fill in a missing intermediate themselves; servers and phones often don't. A chain that "works in Chrome" can still break the app.

  3. 3Automate renewal

    Use ACME on the load balancer (and the CDN's managed certificates where available), renewing at two-thirds of the lifetime.

    Why: A renewal that happens daily, by a bot, can't be forgotten when someone leaves. Renewing early leaves weeks to fix a failing renewal.

  4. 4Alert like it's disk space

    An external check reads every certificate's end date daily and alerts at 30, 14 and 7 days; at 7 days it pages on-call.

    Why: Automation fails silently too (expired DNS token, changed firewall). The alert catches the failure while there's still time.

  5. 5Prove it

    In staging, issue a certificate valid for 2 days and watch the bot renew it and the alert fire if you block the renewal.

    Why: A renewal path that has never run is a hope, not a process.

The whole thing in one line: Lina found every certificate, fixed incomplete chains, handed renewal to a bot and put a daily expiry alert on top, so expiry becomes a routine, watched event instead of a midnight outage.

HTTP methods carry meaning that caches and retry logic rely on. GET and HEAD are safe and cacheable. GET, PUT and DELETE are idempotent. POST is neither, which is why payment endpoints need . Responses say who may keep a copy with Cache-Control, and an lets a cache ask "has it changed?" and get a tiny 304:

http
GET /api/hotels/42 HTTP/1.1
Host: api.stayhub.com

HTTP/1.1 200 OK
Cache-Control: public, max-age=60, stale-while-revalidate=300
ETag: "h42-v918"
Vary: Accept-Language
Strict-Transport-Security: max-age=31536000; includeSubDomains

{"id":42,"name":"Hotel Ribeira","stars":4, ...}

# 90 s later the copy is stale, so the browser revalidates:
GET /api/hotels/42 HTTP/1.1
If-None-Match: "h42-v918"

HTTP/1.1 304 Not Modified
Fresh for 60 s, served stale for up to 300 s while revalidating. The 304 has no body: a few hundred bytes instead of 18 KB.
Cache-Control directiveMeaningTypical use
max-age=NFresh for N seconds; no request neededPhotos, versioned JS (long N)
s-maxage=NFreshness for shared caches (CDNs) onlyPublic pages cached 30 s at the edge
public / privateMay shared caches store it? private = browser onlyprivate for anything per-user
no-cacheStore it, but revalidate before every useHTML that must never be stale
no-storeNever store anywhereBookings, payment pages, personal data
immutableNever revalidate while freshFiles whose URL contains a content hash
stale-while-revalidate=NServe stale for N s while refreshingSearch results, hotel lists
11

Interactive simulation

12

Visual diagram

Click a component

One HTTPS request to a hotel API in a common set-up where TLS ends at a CDN edge (StayHub's api.stayhub.com ends TLS at its own load balancer in Frankfurt). Start the walkthrough.

13

Analogy

  • Calling a hotel deskOne question per call, six phone linesHTTP and TLSHTTP/1.1
  • Calling a hotel deskTen questions on one line, answers numberedHTTP and TLSHTTP/2 multiplexing
  • Calling a hotel deskNot hanging up between questionsHTTP and TLSKeep-alive, reusing connections
  • Calling a hotel deskClerk shows an ID signed by the governmentHTTP and TLSA certificate signed by an authority
  • Calling a hotel deskAgreeing on a secret codeHTTP and TLSTLS session keys
  • Calling a hotel desk"This price list is valid for an hour"HTTP and TLSA Cache-Control header

Where the analogy breaks: a clerk can glance at an ID and use judgement. Your browser checks the certificate with strict maths, and refuses outright if anything is off, including a date one minute past expiry.

14

Check your understanding

Q1/3Reasoning
A guest in Tokyo opens a brand-new HTTPS connection (TCP + TLS 1.3, no resumption) to a server in Frankfurt with a 230 ms round-trip time. Ignoring DNS and server processing, roughly how many milliseconds pass before the first byte of the response arrives?
ms
How confident are you?
15

Practice ladder

Step 1 · Trace

Trace three handshakes

Debugging Warm-up

Three StayHub hostnames, three certificate situations. For each, say whether a browser connects, whether the mobile app's HTTP client connects, and why.

HostCertificate servedDatesChain sent
api.stayhub.comCN = api.stayhub.comvalidleaf + intermediate
partners.stayhub.comCN = api.stayhub.comvalidleaf + intermediate
img.stayhub.comCN = img.stayhub.comvalidleaf only
Step 2 · Complete

Finish Lina's certificate runbook

Design Practice

Lina's runbook for "a certificate alert fired: 7 days left on partners.stayhub.com" has two blank steps. Fill in steps 3 and 5.

  1. Confirm the alert: openssl s_client -connect partners.stayhub.com:443 -servername partners.stayhub.com | openssl x509 -noout -enddate.
  2. Check the renewal bot's log for that hostname.
  3. ___
  4. Fix the cause (for example a renewed DNS API token, or the hostname added to the bot's list), then trigger a renewal.
  5. ___
  6. Write down what broke in the postmortem doc, and add a check so this cause would alert sooner.
Step 3 · Solve

Make the hotel page fast on a second visit

Design Practice

Every resource on the hotel page is served today with:

Cache-Control: no-store
Connection: close

Guests in Spain see 1.8 s loads every time, even on repeat visits. The page has: the HTML (per-guest member prices), /static/app.3f9a.js and /static/app.7c21.css (content hash in the name), 12 hotel photos (change a few times a year), /api/hotels/42 (description, changes a few times a month) and /api/hotels/42/availability (changes every minute, same for everyone).

Propose headers for each, and explain what changes for a second visit.

Step 4 · Decide

HSTS preload for stayhub.com?

Decision Stretch

Lina proposes adding stayhub.com to the browsers' HSTS preload list: browsers would then refuse to connect to stayhub.com or any subdomain over plain HTTP, forever, even on a first visit. Removal takes months.

Facts: every guest-facing host is already HTTPS. But legacy-extranet.stayhub.com, used by 40 small hotels, still runs on plain HTTP on an old server, and a vendor's printer integration at some hotels posts to print.stayhub.com over HTTP.

Write a short decision: "We chose X over Y because…, accepting the risk of…".

16

Explain it yourself

Explain to a junior colleague what happens between fetch('https://api.stayhub.com/hotels/42') and the JSON arriving, and what you would change to make the second call faster.

0 words