To run Django properly over HTTPS, redirect HTTP to HTTPS, mark the session and CSRF cookies secure, then add HSTS last and gradually. If you sit behind a reverse proxy, be careful with SECURE_PROXY_SSL_HEADER, because the Django security docs warn that a wrong value can open CSRF problems.
Step 1: get HTTPS working first
Settings cannot fix a site that does not serve a valid certificate. Get TLS working at your load balancer or web server, confirm every page loads over HTTPS, and only then touch Django settings. Turning on HSTS before this point can lock users out.
Step 2: redirect HTTP to HTTPS
SECURE_SSL_REDIRECT = True makes Django redirect HTTP requests to HTTPS. The Django docs note that with a reverse proxy, the web server may be a better place for the redirect. Pick one place and make it consistent, so you do not get redirect loops.
Step 3: the two cookies
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
The first keeps the session cookie off plain HTTP. The second does the same for the CSRF cookie. These two lines are the cheapest hardening you can do.
Step 4: tell Django about your proxy, carefully
If TLS ends at a proxy, Django sees plain HTTP from the proxy and cannot tell the original request was secure. SECURE_PROXY_SSL_HEADER fixes that by trusting a header the proxy sets. The docs say to set it only if you are behind a proxy and to read its warnings first, because misconfiguration can enable CSRF vulnerabilities.
The rule behind the warning: only trust that header if your proxy strips it from incoming client requests and sets it itself. Otherwise any client can claim to be on HTTPS.
Step 5: HSTS, slowly
HSTS tells browsers to use HTTPS for future visits. The relevant settings are:
SECURE_HSTS_SECONDS: Turns HSTS on and sets how long browsers rememberSECURE_HSTS_INCLUDE_SUBDOMAINS: Extends it to every subdomainSECURE_HSTS_PRELOAD: Allows submission to browser preload lists
Start with a small value for SECURE_HSTS_SECONDS, confirm nothing breaks, then raise it. Include subdomains only after you have checked every subdomain serves HTTPS. Preload submits your domain to browser lists, so treat it as a deliberate decision and check the preload requirements first. You can also set HSTS on the web server instead.
Common mistakes
- Enabling HSTS with a long lifetime before a subdomain has a certificate.
- Setting
SECURE_PROXY_SSL_HEADERwhen the proxy does not overwrite the header. - Doing the redirect in both Django and the proxy and creating a loop.
- Forgetting the cookie flags because the redirect "already handles it".
Quick check
Is SECURE_SSL_REDIRECT enough without secure cookies?
No. A first plain HTTP request can still send cookies before the redirect happens, so set both cookie flags.
Should I set SECURE_HSTS_PRELOAD on day one?
Usually not. Roll out HSTS with a short lifetime first, and treat preload as a deliberate step after everything else works.
Sources
Last reviewed: 19 October 2026.