Forcing HTTPS in .htaccess in an Elastic Beanstalk app

After several sessions of researching how to force a SSL connection in an Apache AWS Elastic Beanstalk app behind an Elastic Load Balancer, I finally hit on a discussion where the problem is clearly explained and a solution is given.

Normally, one can look at the port a request comes in on and force only secure connections by redirecting requests on port 80 to post 443 in your .htaccess file,

This won’t work with an app behind a load balancer that is taking care of the encryption – requests are already on port 80 by the time they reach your app servers and redirecting them will create an infinite loop. End-users will get an error in their browser similar to “This page redirected you too many times (Error: ERR_TOO_MANY_REDIRECTS)”. This happens because,

  • We want the ELB set up to handle SSL encryption as this will reduce the processing load on our app servers
  • ELB does this by decrypting requests coming in over port 443 and forwarding them to an app server on post 80 through our secure VPN
  • To the app server, the requests all look like they are coming in over port 80 – because they are – so the above redirect rule redirects all requests. Requests that came to the ELB over port 443 are redirected by the app server to 443.

We need a way of only redirecting requests that came to the ELB load balancer over port 80.

Fortunately, the load balancer adds a header when it decrypts and forwards a secure request to the app over an insecure port, X-Forwarded-Proto:443. This is the header we need to look for in our .htaccess file. Here is one way to identify the requests that we want to redirect to the secure port – the ones that were not forwarded from a HTTPS request:

An advantage to letting the load balancer handle SSL is that my local development environment doesn’t need to implement SSL. Adding one line to the .htaccess makes the rule only apply when running on a specific domain – if the request is to localhost or 127.0.0.1, the rule is ignored,