Improving Heroku's Suggestions for Django

Let’s start by answering the basic question, what does SECURE_PROXY_SSL_HEADER do?

Take a step back for a moment. We might think that a browser is connecting directly to your project:

[ browser ] ---> https ---> [ Django project ]

However, in the case of a “production-quality” deployment, when you’re using a web server, the connection is actually with the web server. That web server then forwards the request to the Django project:

[ browser ] ---> https ---> [ web server ] ---> ??? ---> [ Django project ]

In the “common case”, that second connection (identified by ???) is going to be http and not https.

What does this mean? It means that Django is going to think that this request is not secured by https, which can and will cause a number of problems in different areas. (If nothing else, it’s likely to cause URLs being generated by the static tag to generate http://... urls and not https://... urls.)

How do we fix this? How do we tell Django that the browser is actually using https?

That is the purpose of the SECURE_PROXY_SSL_HEADER setting.

When you set:

You’re telling Django, to check this header (HTTP_X_FORWARDED_PROTO) which is generated by the web server (not coming from the browser) for the value ‘https’. If that header has that value, then Django knows to treat that request as if it were requested by the browser as https://....

And that’s why the docs have that warning. Django is trusting that the web server is doing the right thing, and if it isn’t, you may have a real problem.

Having said that, this is exactly what we do. We use nginx as the SSL endpoint, and proxy all requests to the backends as http - but telling those endpoints (via that header) that the original requests were all https.

2 Likes