2

Right now I have a SSL enabled website. The SSL is at the ELB level, so the apache http server never sees it. I'm trying to make it so that Apache will force all requests to have https so there is no http requests being made. I was reading several other posts on SO including this:

Django and SSL question

https://serverfault.com/questions/410542/disable-https-for-certain-path-in-nginx-results-in-instance-behind-elb-going-int

http://www.acmedata.in/2012/08/31/how-to-host-a-django-app-behind-elb-with-ssl/

Can I make use of ELB configuration for this? Or do I have to remove the private key, etc. from the ELB and put it all at the web server level? I was unable to find any further information regarding this...

Community
  • 1
  • 1
KVISH
  • 12,923
  • 17
  • 86
  • 162

2 Answers2

5

You can force https by adding a rewrite rule like this to your Apache configuration:

<VirtualHost *:80>
    ...
    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=permanent]
    ...
</VirtualHost>

The key here is the X-Forwarded-Proto header. The ELB handles https and forwards requests to Apache as http, and it also adds this header in the process. The rewrite rule checks this header to only redirect http requests that don't originate from the ELB.

David Levesque
  • 22,181
  • 8
  • 67
  • 82
2

You can handle this at the django level, this is what I use:

from django.http import HttpResponsePermanentRedirect
from django.conf import settings


class SecureRequiredMiddleware(object):
    def __init__(self):
        self.paths = getattr(settings, 'SECURE_REQUIRED_PATHS')
        self.enabled = self.paths and getattr(settings, 'HTTPS_SUPPORT')

    def process_request(self, request):
        if self.enabled and not request.is_secure():
            full_path = request.get_full_path()

            for path in self.paths:
                if full_path.startswith(path):
                    secure_url = request.build_absolute_uri(full_path).replace(
                        'http://', 'https://')
                    return HttpResponsePermanentRedirect(secure_url)

Add that to a file and point to it with your middleware settings. Then you will need to add two settings items. The first is called SECURE_REQUIRED_PATHS and it should be a list of URL's like so:

SECURE_REQUIRED_PATHS = [
    '/login',   #  require HTTPS for any URL starting with `/login`
    '/account', # require HTTPS for any URL starting with `/account`
    '/',        # require HTTPS for all URLs
]

The second should be a flag called HTTPS_SUPPORT:

HTTPS_SUPPORT = True

Then anytime a user access a URL in your SECURE_REQUIRED_PATHS with HTTP, they will be redirected to the HTTPS equivalent.

Ron E
  • 2,214
  • 2
  • 16
  • 14
  • But does this creat https links on the page? Or is it just redirecting every request? I'd rather not do that... – KVISH Aug 30 '13 at 04:29
  • It will only redirect requests destined to URL's in your SECURE_REQUIRED_PATHS setting. Putting the certificate on the application node instead of the ELB is a non-option iirc as the ELB needs to be able to decrypt the SSL stream before it can actually do load balancing. – Ron E Aug 30 '13 at 18:56
  • I understand that, but that's not the right way. Right way is the other solution... because it will rewrite the URL at the http server. This code will make it reach the app first and then it will re run every request (as long as its in the required https paths). – KVISH Aug 31 '13 at 17:14
  • What's the concern here, loss of performance due to responding to a rewrite request? You can adjust your middleware settings in such a way that this is activated first, and if your clients are caching they will cache the permanent redirect. I very much doubt you'll even notice this middleware and in fact something like this will be required to run a django app on heroku without a custom build. – Ron E Aug 31 '13 at 23:44