We always host Django app behind a proxy server(apache or nginx) in production, the connection from your client and the proxy server may be(better be) https. However, between the proxy server and Django app(gunicorn or whatever you’re using) is usually http
. So Django thinks that the client is using http
, and returns all hyperlink including media link & hyperlink fields using http
protocol.
Solution One
This sometimes is not a big problem, as we can force all http
connection to our proxy server to use https like the following.
Redirect permanent / https://example.com/
This may solve the security problem but what if your client does not support http
(IOS, WechatApp etc.)?
Solution Two(prefered)
The best way to solve this is to let Django know the protocol that your client is using.
As per Django’s documentation, it uses request
object’s is_secure()
method to determine if the caller is using https. Since the headers are stripped by our proxy server, is_secure()
will always return False
resulting in http
appears in hyperlinks.
Now we know the reason behind this, solving the problem becomes trivial.
Use one of Django’s setting
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
this means that if the request has a header X_FORWARDED_PROTO
with value https
, Django considers it to be secure and will use https
in hyperlinks.
And don’t forget to forward protocol in your proxy server, here is an example in Apache.
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
Problem solved 🙂