Python Https Local Development Setup

Written by

in

Developing web applications with Python often starts on a local machine, but as soon as you need to test OAuth callbacks, secure cookies, or third‑party APIs, plain HTTP quickly becomes a bottleneck. Setting up a reliable HTTPS local development environment not only mirrors production conditions but also eliminates “mixed‑content” warnings and keeps sensitive data encrypted even during debugging. In this guide we walk through everything you need—self‑signed certificates, tools like mkcert, framework‑specific configurations, and Docker tricks—so you can spin up a secure Python server in minutes.

Why Use HTTPS for Local Development?

  • Security compliance: Modern browsers block insecure origins from accessing geolocation, camera, or payment APIs.
  • OAuth & SSO: Providers such as Google, GitHub, and Azure require a https:// redirect URI, even in dev.
  • Feature parity: Testing CSP, HSTS, and secure cookie flags works exactly as they will in production.
  • Future‑proofing: Once HTTPS is baked into your workflow, moving to a cloud host becomes a simple copy‑paste.

Prerequisites

  • Python 3.8+ installed (virtual environments recommended)
  • OpenSSL (usually pre‑installed on macOS/Linux; Windows users can use Git Bash)
  • One of the following web frameworks: Flask, Django, FastAPI, or a plain http.server
  • Optional but highly recommended: mkcert for trusted local certificates

Generating a Self‑Signed Certificate with OpenSSL

If you prefer the classic approach, OpenSSL can create a certificate that browsers will accept after you add it to the trust store.

Step‑by‑step commands

# Create a private key
openssl genrsa -out localhost.key 2048

# Generate a certificate signing request (CSR)
openssl req -new -key localhost.key -out localhost.csr \
    -subj "/C=US/ST=California/L=SanFrancisco/O=MyDev/CN=localhost"

# Sign the certificate (valid for 365 days)
openssl x509 -req -days 365 -in localhost.csr -signkey localhost.key -out localhost.crt

# Verify the pair
openssl x509 -in localhost.crt -text -noout

Place localhost.key and localhost.crt in a secure folder (e.g., certs/) and reference them in your Python server.

Using mkcert for Trusted Local Certificates

Self‑signed certificates trigger warnings unless you manually trust them. mkcert automates the process by creating a local CA and issuing certificates that browsers trust out of the box.

Installation

  • macOS: brew install mkcert && brew install nss # for Firefox
  • Linux (Debian/Ubuntu): sudo apt install libnss3-tools then curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" and chmod +x mkcert
  • Windows: choco install mkcert or download the binary from the GitHub releases page.

Creating the cert

# Generate and install a local CA (run once)
mkcert -install

# Create a cert for localhost and any subdomains you need
mkcert localhost 127.0.0.1 ::1

This command produces localhost+2.pem (certificate) and localhost+2-key.pem (private key). They can be used directly with any Python server.

Framework‑Specific HTTPS Configuration

Flask

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return "Secure Flask!"

if __name__ == '__main__':
    # For development only – use a production WSGI server in prod
    app.run(host='0.0.0.0', port=5000, ssl_context=('certs/localhost.crt', 'certs/localhost.key'))

Django

Django’s built‑in development server can serve HTTPS with the runsslserver package.

# Install the helper
pip install django-sslserver

# Add to INSTALLED_APPS in settings.py
INSTALLED_APPS += ['sslserver']

# Run with SSL
python manage.py runsslserver 0.0.0.0:8000 \
    --certificate certs/localhost.crt \
    --keyfile certs/localhost.key

FastAPI / Uvicorn

import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Secure FastAPI"}

if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8443,
        ssl_certfile="certs/localhost.crt",
        ssl_keyfile="certs/localhost.key",
    )

Plain http.server (Python 3.7+)

import http.server
import ssl

server_address = ('', 4443)
httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)

# Wrap socket with SSL
httpd.socket = ssl.wrap_socket(
    httpd.socket,
    server_side=True,
    certfile='certs/localhost.crt',
    keyfile='certs/localhost.key',
    ssl_version=ssl.PROTOCOL_TLS,
)

print("Serving HTTPS on port 4443")
httpd.serve_forever()

Dockerizing a Secure Python Service

Containers add isolation, but they also require you to mount the certificates or build them inside the image.

Dockerfile example (Flask)

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

# Copy source and certs
COPY . /app
COPY certs/localhost.crt /etc/ssl/certs/
COPY certs/localhost.key /etc/ssl/private/

EXPOSE 5000

CMD ["python", "app.py"]

Run with:

docker build -t secure-flask .
docker run -p 5000:5000 secure-flask

Testing Your HTTPS Setup

  • Browser test: Open https://localhost:5000 (or the port you chose). You should see a lock icon if the cert is trusted.
  • cURL verification: curl -vk https://localhost:5000 shows the TLS handshake details.
  • Postman / Insomnia: Import the same URL; these tools automatically trust mkcert certificates.

Common Pitfalls & How to Fix Them

  • “CERTIFICATE_VERIFY_FAILED” errors: Ensure the CA generated by mkcert -install is in your system’s trust store. On Linux, you may need to update /etc/ssl/certs/ca-certificates.crt.
  • Port conflicts: Default HTTPS ports are 443, 8443, or 5001. Choose a free port and update firewall rules if needed.
  • Mixed‑content warnings: All assets (CSS, JS, images) must be loaded over https://. Use relative URLs or protocol‑agnostic // prefixes.
  • Docker networking: When using Docker Desktop, localhost inside the container refers to the container itself. Map ports correctly and use host.docker.internal for host‑to‑container communication.

Automating Certificate Renewal

Self‑signed certificates expire after a set period (often 365 days). Automate regeneration with a simple shell script or a Makefile target:

# Makefile
cert:
\tmkcert -install
\tmkcert localhost 127.0.0.1 ::1

renew:
\tmake cert

Run make renew weekly via cron or Task Scheduler to keep the dev environment hassle‑free.

SEO‑Friendly Keywords to Remember

When you write documentation, blog posts, or README files, sprinkle these terms to improve discoverability:

  • Python HTTPS local development
  • self‑signed SSL certificate Python
  • mkcert Python tutorial
  • Flask HTTPS development server
  • Django SSL local setup
  • FastAPI HTTPS Docker
  • local OAuth callback HTTPS

Conclusion

Switching from plain HTTP to a fully functional HTTPS local development setup is no longer a daunting chore. Whether you rely on OpenSSL for a quick self‑signed pair or prefer the hassle‑free trust

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *