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:
- Python 3.9+ (
python --version) piporpipenvfor package management- OpenSSL (usually pre‑installed on macOS and Linux; Windows users can get it via Win32 OpenSSL)
- 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.AsyncClientwithverify=Falsefor quick unit tests. - Selenium / Playwright: Launch browsers with
--ignore-certificate-errorsto 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
*.keyand*.crtto.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
.envand load them withpython-dotenv. - Enable HSTS in dev (optional): Add
Strict-Transport-Securityheader to test caching behavior. - Run linting and security scans: Tools like
banditcan flag insecure TLS configurations.
Leave a Reply