What you'll learn
- What plain HTTP exposes to anyone on the same network
- The two things TLS provides: encryption and proof of identity
- What a certificate is and what the padlock does and does not promise
- Why modern hosts issue and renew certificates without asking you
- How to spot mixed content and remove hardcoded http:// URLs
on this page
Deploy a project to Cloudflare Pages or Netlify and look at the address bar: https://your-project.pages.dev, padlock and all. You never bought a certificate. You never touched a setting with the word security in it. It was just there.
Most explanations of that padlock either wave it off (“it means the site is secure”) or bury you in cryptography. The useful version sits in the middle, and it’s worth twenty minutes, because HTTPS is something you get for free right up until you break it with one hardcoded URL.
Start with the problem it solves.
What plain HTTP sends in the clear
HTTP (HyperText Transfer Protocol) is the request-and-response language browsers and servers speak. The detail tutorials skip: it’s plain text on the wire. A login over plain HTTP looks like this as it crosses the network:
POST /login HTTP/1.1
Host: myapp.example
Cookie: session=8f3acd02
Content-Type: application/x-www-form-urlencoded
[email protected]&password=hunter2
That is the literal traffic. The URL, the cookie that identifies your logged-in session, the password. Every machine that handles the request on its way to the server can read all of it.
“Every machine” is a longer list than it feels like. On coffee shop wifi it includes anyone on the same network running a packet capture tool; Wireshark is free, and on an open network, reading strangers’ HTTP with it is a beginner exercise. It includes the router the shop bought used and never updated. Past the wifi it includes your ISP (Internet Service Provider) and every network between there and the server. None of this is hypothetical: ISPs have been caught injecting their own ads into pages served over plain HTTP, which only works because they can read and rewrite the traffic in transit.
So plain HTTP means anything you send or receive is readable, and editable, by the network it crosses. That’s the baseline. Now the fix.
What TLS actually gives you
TLS (Transport Layer Security) is the S in HTTPS. You’ll also hear SSL (Secure Sockets Layer), its obsolete predecessor; the protocol was replaced years ago but the old name survives in phrases like “SSL certificate.”
Before any HTTP gets sent, the browser and server run a short negotiation called the handshake, and it buys you two distinct things:
Encryption. The two sides agree on keys, and everything after that point is gibberish to observers. The path you requested, the headers, the cookies, the form body with your password: unreadable to the coffee shop, the router, and the ISP.
Identity. The server proves it really is the server for the domain you typed, rather than some other machine on the network answering in its place.
The second one is underrated, because encryption alone is close to worthless. On a hostile network, anything can claim to be yourbank.com and offer to encrypt traffic with you, and you’d have a beautifully private conversation with the attacker. Encryption only helps once you know who’s on the other end. That proof of identity is the certificate’s job.
One honest caveat so your mental model stays accurate: TLS hides what you did on a site, but the network can generally still tell which site you connected to. The domain name is visible during connection setup. Encrypting your traffic to example.com doesn’t hide the fact that you went there.
Certificates: a signed statement from someone your browser trusts
A certificate is a small file that says, in effect, “the holder of this cryptographic key controls myapp.example,” signed by a certificate authority (CA). Your browser and operating system ship with a list of CAs they trust. During the handshake the server presents its certificate, and the browser checks the signature, the domain name, and the expiry dates against that built-in list. If everything checks out, identity is established and the padlock appears.
How does a CA know you control a domain? It makes you prove it: serve a specific token at a specific URL on that domain, or publish a specific DNS record. Either one is something only the person controlling the domain or its DNS can pull off.
Notice what that check covers and what it doesn’t. It’s a machine-checkable test of domain control. Nobody investigates who you are, whether your company exists, or whether your site is a scam.
Which leads to the most important sentence in this guide: the padlock means the connection is private and that you’re talking to the domain in the address bar. It says nothing about whether that domain deserves your trust. A phishing site at paypal-login-verify.example can get a perfectly valid certificate in minutes, and they do, routinely. Browser vendors know the padlock gets over-read, which is part of why they’ve spent recent years shrinking it or swapping it for a plainer icon.
How this became free and automatic
For most of the web’s history, certificates were a chore. You paid a CA a yearly fee, generated keys with openssl incantations, pasted the results into a dashboard, installed the files on your server, and set a calendar reminder for the expiry date. Then half the internet ignored the reminder, and expired certificates took down real sites on a regular schedule.
In 2015 a nonprofit CA called Let’s Encrypt changed the economics: free certificates, issued and renewed by software instead of by a person. The software side is a protocol called ACME (Automatic Certificate Management Environment). Your server proves domain control automatically, receives a certificate, and repeats the trick before expiry. Let’s Encrypt certificates are short-lived on purpose, roughly 90 days, because no human is supposed to be in the loop anyway, and the wider industry keeps voting to shorten certificate lifetimes further.
Hosting platforms folded that automation in. Deploy to Cloudflare Pages, Netlify, or Vercel and the platform provisions a certificate for your *.pages.dev or *.netlify.app subdomain before you’ve finished reading the build log. Attach a custom domain and it does the same for that, then renews forever. There’s no step where they ask about it because there’s no decision left to make. The right answer is always “yes, HTTPS,” so they stopped asking.
That’s why the padlock was just there. Someone else does the chore now, permanently.
Mixed content: an https page dragging http behind it
Even with HTTPS on the page itself, there’s still one way to leak: load some of the page’s pieces over plain HTTP. An https:// page that requests an http:// image, script, or stylesheet is serving mixed content, and the browser complains in the console with something like:
Mixed Content: The page at 'https://myapp.example/' was loaded over HTTPS,
but requested an insecure resource 'http://old-cdn.example/photo.jpg'.
What happens next depends on the resource. For images and media, modern browsers first try rewriting the URL to https:// on the fly, and block the request if the server can’t answer securely. Scripts and stylesheets get harsher treatment: blocked outright, no retry. A script fetched over plain HTTP could be rewritten by the network into anything, and a rewritten script can do anything to your page, so browsers refuse to gamble. The visible symptom is a page with missing images or quietly broken behavior, plus a console full of warnings like the one above.
The cause is almost always a URL you typed long ago or copied from an old tutorial: a font link, a hotlinked image, an API base URL. The fix is mechanical. Serve your own assets with relative paths (/images/photo.jpg inherits the page’s protocol automatically) and write https:// for anything external.
Why localhost gets a pass
After all this you might wonder why http://localhost:3000 has never warned you about anything. Browsers treat localhost as a secure context on purpose: traffic to localhost never leaves your machine, so there’s no network in the middle and nobody positioned to listen. Encryption would be protecting the data from you.
This is also why browser features that insist on HTTPS, like service workers, clipboard access, and geolocation, work fine in local dev. The exception shows up the day you test from your phone using your laptop’s network address, something like http://192.168.1.20:3000. A real network address isn’t localhost, the pass doesn’t apply, and the secure-only features stop working. A tool called mkcert can mint locally trusted certificates for exactly that situation. File the name away; you won’t need it for a while.
The one job your host leaves you
Encryption, certificates, and renewal are handled. What remains for you is small, and it still trips people: make sure plain HTTP can’t sneak back in.
First half: every request to http://yourdomain should be redirected to https://yourdomain before any content is served. Otherwise a visitor who types the bare domain, or follows an ancient http:// link, gets the readable-by-everyone version. Platforms mostly cover this too. Netlify and Vercel redirect for you, and Cloudflare has a setting literally named “Always Use HTTPS” worth confirming. Trust it, then verify, because the check takes ten seconds. curl -I sends a request and prints only the response headers:
curl -I http://raindev.fyi HTTP/1.1 301 Moved Permanently Location: https://raindev.fyi/
Headers trimmed. The plain-HTTP side serves no content at all, just a permanent redirect to the secure version.
curl -I https://raindev.fyi HTTP/2 200
The real response only exists on the https side. If the first command returns 200 with actual content, your redirect is missing.
If you ever graduate to running your own server, the same automation follows you: certbot, the standard Let’s Encrypt client, sets up both the certificate and the redirect when you run certbot --nginx.
Second half: stop hardcoding http:// in your own code. Search for it:
# Find every hardcoded http:// URL in your source
grep -rn "http://" src/
Some hits are fine, like a markdown link to an old site that never adopted HTTPS. The ones to fix are the load-bearing URLs: API base URLs, image and font sources, anything your deployed page will actually fetch. Own assets become relative paths. External resources become https://. API base URLs move into environment variables, and the value you set in the host’s dashboard starts with https://.
The payoff lands the first time you wire a deployed frontend to a deployed backend. Your page on Netlify is https://, and if the fetch call inside it points at http://my-api.example, the browser blocks it as mixed content and your app breaks only in production, the most annoying possible place. Put https:// in the env var, keep the redirect in place, and the whole subject goes back to being something your host quietly handles while you build the actual project.
signal check
Can you answer these without scrolling back up?
-
A site has a valid certificate and shows a padlock. Is it safe to type your card number in?
Not on that evidence alone. The padlock means the connection is encrypted and the server proved it controls the domain in the address bar. It says nothing about who runs that domain. Phishing sites get valid certificates routinely, so check the domain name itself.
-
Your HTTPS page loads an image from an http:// URL. What does the browser do?
It treats the request as mixed content. For images and media, modern browsers try rewriting the URL to https:// first and block it if the server can't answer securely. Scripts and stylesheets over http:// get blocked outright, because tampered active content can rewrite the whole page.
-
Why can you develop on http://localhost without certificate warnings?
Browsers treat localhost as a secure context. Traffic to localhost never leaves your machine, so there is no network in between and nobody positioned to eavesdrop.
progress is stored in this browser only