Python Https Local Development Setup

Written by

in

Developing web applications with Python is a breeze, but when you need to test HTTPS locally, the process can feel a bit daunting. In this guide we’ll walk you through a step‑by‑step Python HTTPS local development setup that works with popular frameworks like Flask and Django, covers self‑signed certificates, and even shows how to integrate tools such as mkcert and ngrok. By the end of this post you’ll have a secure, repeatable environment that mirrors production, boosts your confidence, and improves SEO‑friendly testing.

Why Use HTTPS in Local Development?

Running your app over HTTPS locally isn’t just a nicety; it’s a best practice that brings several tangible benefits:

  • Accurate browser behavior: Modern browsers block mixed content, so testing with HTTP can hide bugs that only appear under HTTPS.
  • OAuth and third‑party APIs: Many services (Google, Stripe, etc.) require a secure redirect URI, making a local HTTPS endpoint essential.
  • Security‑first mindset: Early exposure to TLS configuration reduces the risk of misconfigurations when you go live.
  • SEO testing: Search engines treat HTTPS as a ranking signal; testing locally helps catch canonical URL issues early.

Prerequisites

Before diving in, make sure you have the following installed on your development machine:

  1. Python 3.9+ (python --version)
  2. pip or pipenv for package management
  3. OpenSSL (usually pre‑installed on macOS and Linux; Windows users can get it via Win32 OpenSSL)
  4. A code editor of your choice (VS Code, PyCharm, etc.)

Generating a Self‑Signed Certificate

The simplest way to enable HTTPS is to create a self‑signed certificate. While browsers will show a warning, you can add an exception for development purposes.

Step‑by‑step with OpenSSL

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

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

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

After running these commands you’ll have dev.key (the private key) and dev.crt (the certificate) in your project folder.

Using mkcert for Browser‑Trusted Certs

If you’d rather avoid browser warnings, mkcert creates certificates that are trusted by your local machine out of the box.

# Install mkcert (macOS example)
brew install mkcert
brew install nss # for Firefox support

# Create a local CA (once)
mkcert -install

# Generate a cert for localhost
mkcert localhost 127.0.0.1 ::1

This command produces localhost+2.pem (certificate) and localhost+2-key.pem (key) which can be used directly in Python servers.

Integrating HTTPS with Flask

Flask’s built‑in development server can serve HTTPS with a single line of code. Below is a minimal example using the self‑signed cert we created earlier.

from flask import Flask

app = Flask(__name__)

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

if __name__ == '__main__':
    # Pass the certificate and key files to the run() method
    app.run(host='127.0.0.1', port=5000, ssl_context=('dev.crt', 'dev.key'))

Run the script with python app.py and open https://localhost:5000. Remember to accept the security exception if you used a self‑signed cert.

Hot‑Reload with HTTPS

Flask’s debug=True flag enables auto‑reloading, but you need to pass the SSL context as a tuple. Here’s a developer‑friendly version:

app.run(
    host='0.0.0.0',
    port=8443,
    debug=True,
    ssl_context=('dev.crt', 'dev.key')
)

Now you can edit your code and see changes instantly while staying under HTTPS.

Configuring HTTPS in Django

Django’s development server does not natively support HTTPS, but you can wrap it with runsslserver or use uvicorn for ASGI projects.

Option 1: Using django-sslserver

# Install the package
pip install django-sslserver

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

# Run the HTTPS server
python manage.py runsslserver 0.0.0.0:8000 \
    --certificate dev.crt --key dev.key

This command starts Django on https://localhost:8000 with your custom certificate.

Option 2: Using uvicorn for Django Channels or ASGI

# Install uvicorn
pip install uvicorn

# Run with SSL
uvicorn myproject.asgi:application \
    --host 0.0.0.0 --port 8443 \
    --ssl-keyfile dev.key --ssl-certfile dev.crt

Both approaches let you test middleware, security headers, and CSP policies exactly as they will behave in production.

Automating Certificate Generation with a Makefile

To keep your workflow smooth, add a simple Makefile (or a scripts folder) that regenerates certificates whenever needed.

.PHONY: cert clean

cert:
    @echo "Generating a fresh self‑signed certificate..."
    openssl req -x509 -nodes -days 365 \
        -newkey rsa:2048 \
        -keyout dev.key -out dev.crt \
        -subj "/CN=localhost"

clean:
    rm -f dev.key dev.crt dev.csr

Now you can run make cert before starting your server, ensuring the cert is always up‑to‑date.

Testing HTTPS with Automated Tools

Once your local server runs over HTTPS, you can integrate it with testing suites:

  • pytest‑httpx: Use httpx.AsyncClient with verify=False for quick unit tests.
  • Selenium / Playwright: Launch browsers with --ignore-certificate-errors to automate UI tests.
  • curl: Simple command‑line verification: curl -k https://localhost:5000

Example pytest fixture

import pytest
import httpx

@pytest.fixture
def client():
    return httpx.Client(base_url="https://localhost:5000", verify=False)

def test_homepage(client):
    response = client.get("/")
    assert response.status_code == 200
    assert "Secure Flask app" in response.text

This fixture works for both Flask and Django projects, giving you confidence that your HTTPS routes behave correctly.

Sharing Your Local HTTPS Server with the World (Optional)

Sometimes you need to demo a feature to a remote stakeholder. Tools like ngrok expose a secure tunnel to your local HTTPS server without extra configuration.

# Install ngrok (example)
brew install ngrok

# Start a tunnel to your local Flask server
ngrok http 5000

# ngrok will output a public HTTPS URL like:
# https://abcd1234.ngrok.io

The tunnel inherits TLS from ngrok, so you don’t need to worry about certificate warnings on the remote side.

Best Practices for a Secure Local Environment

  • Never commit private keys: Add *.key and *.crt to .gitignore.
  • Rotate certificates regularly: Even in dev, short‑lived certs reduce the risk of accidental exposure.
  • Use environment variables: Store paths to your certs in .env and load them with python-dotenv.
  • Enable HSTS in dev (optional): Add Strict-Transport-Security header to test caching behavior.
  • Run linting and security scans: Tools like bandit can flag insecure TLS configurations.

Full

Comments

Leave a Reply

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