23.7. HTTPS Configuration
Table of Contents
Why HTTPS Configuration Matters
When you ship a backend application to real users, you must protect three things: the data in transit, the identity of your server, and the integrity of the traffic. HTTPS solves all three.
HTTPS is simply HTTP over TLS. You keep all the HTTP concepts from earlier (methods, status codes, headers), but the connection is encrypted and authenticated by a TLS layer.
Rule: All production backends that handle real users or sensitive data must use HTTPS, never plain HTTP.
In this chapter you will learn how HTTPS configuration fits into a backend deployment, how TLS certificates work, and how to put all the pieces together with a reverse proxy such as Nginx or a containerized setup.
You will not learn TLS internals here. Focus on what you need as a backend developer to configure and operate HTTPS in practice.
Core Concepts for HTTPS Setup
Before touching configuration files, you need a few practical concepts.
TLS vs SSL
You will see both terms used in docs and configs.
- SSL is the old protocol name, now obsolete.
- TLS is the modern protocol that replaced SSL.
Many tools still say “SSL certificate,” but they really mean a TLS certificate. In this course we will simply say “certificate” or “TLS certificate.”
Certificates, Keys, and Trust
A working HTTPS setup always involves at least:
- A private key (kept secret on your server).
- A certificate (public, sent to clients).
- A trusted Certificate Authority (CA) that signs your certificate.
Rule: Never expose or commit your private key to version control, logs, screenshots, support tickets, or chat.
At a high level:
- You generate a key pair on your server.
- You prove to a CA that you control a domain.
- The CA issues a certificate bound to that domain.
- You configure your web server or reverse proxy to use the certificate and private key.
- Browsers and clients trust your certificate because they already trust the CA.
Typical HTTPS Architecture in Backend Deployments
Most production setups use a reverse proxy in front of the application server:
| Layer | Role | Example tools |
|---|---|---|
| Client | Browser or mobile app | Chrome, curl |
| Reverse proxy | Terminates TLS, handles HTTPS | Nginx, Traefik, Caddy |
| Application server | Runs your backend application | Uvicorn, Gunicorn |
In many real deployments:
- Clients connect to
https://yourdomain.com. - The reverse proxy (for example Nginx) listens on port 443, handles TLS, and forwards the request to your app.
- Your app listens on an internal port, for example 127.0.0.1:8000 or a Docker network port, usually plain HTTP.
Your HTTPS configuration usually focuses on the reverse proxy, not the application itself.
Preparing for HTTPS
Before you configure HTTPS, you typically need:
- A domain name pointing to your server’s public IP (covered in earlier chapters).
- Ports 80 and 443 open on the server.
- Root or sudo access on the server.
You can test from your local machine:
ping yourdomain.comYou should see replies from your server’s IP.
If you are behind a provider firewall or cloud security group (like AWS Security Groups), ensure:
- Port 80 (HTTP) is open, often needed by tools like Let’s Encrypt for validation.
- Port 443 (HTTPS) is open for users.
Self-Signed vs CA-Signed Certificates
There are two main ways to get a certificate:
| Type | Trust in browsers | Typical use |
|---|---|---|
| Self-signed | Not trusted | Internal testing or development |
| CA-signed (public) | Trusted | Production sites, real users |
Self-signed certificate example (for local or internal testing)
On a Linux server you can create a self-signed certificate with OpenSSL:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
This will ask several questions. The most important field is Common Name (CN), where you enter your domain or IP, for example api.localtest.me.
Then you would configure your reverse proxy with:
cert.pemas the certificate.key.pemas the private key.
Browsers will show a security warning, since there is no trusted CA.
CA-signed certificate for production
For real users you must use certificates signed by a trusted CA. Common options:
- Free:
- Let’s Encrypt
- Paid:
- DigiCert, GlobalSign, Sectigo, etc.
Most modern deployments use Let’s Encrypt because it is free and automated.
Automating HTTPS with Let’s Encrypt and Certbot
Let’s Encrypt issues free certificates and Certbot is a common tool to obtain and renew them automatically.
The exact commands depend on your OS and web server, but the flow is similar.
Typical Certbot flow with Nginx
- Install Nginx and Certbot:
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx- Ensure your Nginx server block is set up for your domain on port 80:
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
}
}- Run Certbot:
sudo certbot --nginx -d api.example.comCertbot will:
- Talk to Let’s Encrypt.
- Prove you control
api.example.comusing an HTTP challenge on port 80. - Obtain a certificate and private key.
- Update your Nginx configuration to use HTTPS.
- Certbot will also set up automatic renewal via a cron job or systemd timer.
You can test renewal with:
sudo certbot renew --dry-runRule: Always verify that automatic certificate renewal works. An expired certificate will break HTTPS and your users will see scary browser warnings.
Basic HTTPS Configuration with Nginx
Let us look at a minimal Nginx configuration that terminates HTTPS and forwards traffic to a backend.
Example: HTTP to HTTPS redirect and HTTPS server block
# Redirect all HTTP to HTTPS
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
# HTTPS server
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Key ideas:
- The first server block listens on 80 and redirects all requests to HTTPS.
- The second server block listens on 443 with
sslenabled. ssl_certificateandssl_certificate_keypoint to your certificate and key.- The
proxy_set_headerlines pass important original-request information to your backend.
HTTPS in Containerized Environments (Docker & Docker Compose)
If you use Docker for deployment, you typically keep TLS at the edge of your system:
- Nginx (or another reverse proxy) container handles HTTPS.
- Your application container receives HTTP from Nginx inside a Docker network.
Simple Docker Compose example
docker-compose.yml:
version: "3.8"
services:
app:
image: my-fastapi-app:latest
expose:
- "8000"
nginx:
image: nginx:stable
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
ports:
- "80:80"
- "443:443"
depends_on:
- app
nginx.conf:
events {}
http {
upstream app_backend {
server app:8000;
}
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://app_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}In this setup:
- Certificates are stored on the host under
/etc/letsencryptand mounted read-only into the Nginx container. - Your app runs on a private Docker network and does not handle TLS itself.
Security-focused HTTPS Settings
Beyond basic TLS, you should tune your HTTPS configuration to avoid weak ciphers and insecure protocol versions.
Exact settings change over time, but a common Nginx pattern is:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:...';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;You can generate recommended settings for your server version using tools such as:
- Mozilla SSL Configuration Generator (searchable online).
Rule: Disable old, insecure protocols like SSLv3, TLS 1.0, and TLS 1.1 in production.
HSTS and Redirects
HTTP Strict Transport Security (HSTS) tells browsers to always use HTTPS for your domain.
Example Nginx header:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;max-age=31536000means “remember to use HTTPS for 1 year.”includeSubDomainsapplies to all subdomains too.
Rule: Only enable HSTS for long durations after you are sure your HTTPS configuration is stable and correct. HSTS can “lock in” HTTPS and make mistakes harder to recover from.
You should also ensure all HTTP traffic is redirected to HTTPS with a 301 or 308 redirect, as shown earlier.
Testing and Troubleshooting HTTPS
Once you configure HTTPS, verify that everything works correctly.
Quick local tests
From your machine:
curl -v https://api.example.comLook for:
- SSL/TLS handshake success.
- HTTP status codes, for example
200 OKor301 Moved Permanently.
To see certificate details:
echo | openssl s_client -connect api.example.com:443 -servername api.example.comCheck:
- The certificate subject and issuer.
- The expiration date.
- Any verification errors.
Online tools
You can use external tools (searchable online) that analyze:
- Supported protocols and ciphers.
- HSTS configuration.
- Certificate chain and expiration.
These are useful to double-check your HTTPS security and configuration.
Common HTTPS Configuration Pitfalls
Here are frequent problems you will see in real deployments:
| Problem | Symptom | Fix idea |
|---|---|---|
Wrong server_name | Wrong certificate shown or requests handled by wrong block | Match Nginx server_name to your domain exactly |
| Ports not open | Cannot reach site at all | Open ports 80 and 443 in firewall / security groups |
| Expired certificate | Browser shows “connection not private” | Renew certificate (automatically with Certbot) |
| Missing intermediate certificates | Some clients reject cert | Use full chain file (fullchain.pem with Let’s Encrypt) |
| Certificate for wrong domain | “Certificate does not match hostname” | Request a cert for the exact domain and configure it |
| Forgot redirect from HTTP to HTTPS | Users still access HTTP or mixed-content issues | Add port 80 server block with 301 redirect to HTTPS |
When something breaks:
- Check Nginx error logs.
- Confirm certificate files exist and paths are correct.
- Test from the server itself with
curl https://yourdomain.com.
Practical Checklist for HTTPS Configuration
Use this as a quick reference when you deploy a backend with HTTPS:
- Domain and DNS
- Domain points to your server IP.
- DNS changes have propagated.
- Server basics
- Ports 80 and 443 open on firewall / cloud security group.
- Reverse proxy installed (for example Nginx).
- Certificates
- For production, use Let’s Encrypt or another CA.
- Certbot (or similar) installed and configured for your web server.
- Automatic renewal tested with
certbot renew --dry-run. - Reverse proxy config
server_namematches your domain.- HTTP (port 80) server block redirects to HTTPS.
- HTTPS (port 443) server block uses
ssl_certificateandssl_certificate_key. - Traffic is proxied to your backend app.
- Security options
- Only TLS 1.2 and TLS 1.3 enabled.
- Reasonable cipher suite configuration.
- HSTS considered and optionally enabled correctly.
- Testing
curl -v https://yourdomain.comworks.- Browser shows secure lock icon without errors.
- Online SSL checker shows no critical issues.
If you walk through this list step by step, you can consistently bring up a secure HTTPS endpoint for your backend application.
Views: 7
KAHIBARO