SSL/TLS & HTTPS
HTTPS is table stakes: browsers mark plain HTTP as "Not Secure," search engines rank it down, and modern web features (service workers, geolocation) refuse to run without it. The good news: certificates are free now, and Nginx's part is about six lines.
💡 The Bottom Line
HTTPS = HTTP inside a TLS tunnel, proven by a certificate a trusted
authority issued for your domain. In Nginx: listen 443 ssl + paths to the
certificate and key, plus a tiny port-80 server that redirects everything to HTTPS.
Let's Encrypt issues the certificates free, and Certbot
automates both the config and the renewals.
The two server blocks
# 1. The real site, on 443
server {
listen 443 ssl;
server_name mysite.com;
ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem;
root /var/www/mysite;
index index.html;
}
# 2. Port 80 exists only to redirect
server {
listen 80;
server_name mysite.com;
return 301 https://$host$request_uri;
}
That's the whole shape: TLS terminates at Nginx (the encrypted tunnel ends here — this is
called TLS termination), and anything Nginx proxies to backends travels on
your internal network as plain HTTP with X-Forwarded-Proto: https telling the
app the client connection was secure. The 301 redirect makes plain-HTTP visits
land on HTTPS automatically.
Free certificates: Let's Encrypt + Certbot
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d mysite.com -d www.mysite.com
Certbot proves to Let's Encrypt that you control the domain (it answers a challenge request on your server), obtains the certificate, edits your Nginx config for you — adding the ssl lines and the redirect — and installs a timer that renews automatically. Let's Encrypt certificates last 90 days by design: short enough that automation isn't optional, which is the point.
🙋 There Are No Dumb Questions
Q: SSL or TLS — which is it?
A: TLS. SSL was the original 1990s protocol; TLS is its successor, and every SSL version has
been deprecated for years. The old name just stuck to everything — "SSL certificate,"
ssl_certificate in Nginx config — so both names refer to the same thing in
practice. Say either; configure TLS.
⚠️ Watch Out
The privkey.pem file is the crown jewels — anyone holding it can impersonate
your site. Never commit it to git, never paste it into chat/tickets, and keep it readable
by root only (Certbot sets this up correctly). If a key ever leaks, revoke the certificate
and issue a new one — renewal is free and instant, embarrassment is neither.
🔧 Try It Yourself
No domain handy? Practice the config shape with a self-signed certificate (browsers will warn — that's expected, it proves the encryption without a trusted authority):
openssl req -x509 -newkey rsa:2048 -nodes -days 30 \
-keyout key.pem -out cert.pem -subj "/CN=localhost"
Mount both into the nginx-lab container with a server block using
listen 443 ssl; and the two ssl_ directives, publish
-p 8443:443, and open https://localhost:8443. Click through the
warning — the padlock machinery is all there, just unsigned.
✅ Quick Check
Why do Let's Encrypt certificates expire after only 90 days?
Last lesson: the Nginx traps everyone hits once — the trailing-slash proxy_pass surprise, location matching order, and friends.