Lesson 5 of 6

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.

← Back to
Next →