The specific scenario I'm dealing with is attempting to connect to a websocket connection behind an AWS elastic load balancer, whilst enforcing https/ssl rather than http/tcp.
To enable the TCP/SSL upgrade from http/s, the protocol on the load balancer has necessarily been set to TCP rather than HTTP on port 80 and SSL rather than HTTPS on 443, both of which are forwarded onto the instance port of 80 using TCP.
However, a side effect of setting the protocol to TCP/SSL is that the x-forwarded-proto
header no longer gets set, as experienced here:
Amazon Elastic load balancer is not populating x-forwarded-proto header
This makes the next challenge of 301ing any incoming requests using http/tcp to https/ssl somewhat problematic, as this typically relies on the inspecting the x-forwarded-proto
header.
A little more detail on the specifics of the situation: there exists a docker container with a Meteor.js process running inside of it, which resides in turn within an AWS Elastic Beanstalk Application (which has an Nginx proxy layer by default, but this isn't accessible due to the use of docker which simply pulls a container definition from docker hub), which sits behind the aforementioned ELB.
Ultimately I'm left inspecting the headers that I have available to my application by the time the request has gone through the ELB, Nginx and docker agent layers, trying to work out if the original request made by the client started with http or https
Incoming https://
request headers:
{
host: 'whatever.elasticbeanstalk.com',
'x-real-ip': '999.99.99.99',
'x-forwarded-for': '999.99.99.99',
'cache-control': 'max-age=0',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36',
'accept-encoding': 'gzip, deflate, sdch',
'accept-language': 'en-US,en;q=0.8'
}
Incoming http://
request headers:
{
host: 'whatever.elasticbeanstalk.com',
'x-real-ip': '999.99.99.99',
'x-forwarded-for': '999.99.99.99',
'cache-control': 'max-age=0',
accept: 'image/webp,image/*,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36',
'accept-encoding': 'gzip, deflate, sdch',
'accept-language': 'en-US,en;q=0.8',
'if-none-match': '"141699-1446507991000"',
'if-modified-since': 'Mon, 02 Nov 2015 23:46:31 GMT'
}
The only one of these that looks vaguely useful is the upgrade-insecure-requests
header, but based on this
What is the "Upgrade-Insecure-Requests" HTTP header?
I'm pretty sure it's not.
Maybe I'm missing something however...
When you use TCP, the ELB will not inject HTTP headers such as x-forwarded-proto or x-forwarded-for. You may be able to get what you need by configuring Proxy Protocol.
If the question is in fact "How can I ensure anyone visiting my website via http is redirected to https/ssl" (as indeed it turned out that this is what I meant), this is possible by
Setting the Elastic Load Balancer to forward HTTP on 80 to HTTP on 80 on the instance (rather than TCP on 80 as it was before) and then forward HTTPS on 443 to TCP on 80 on the instance.
"Assuming HTTPS/SSL" during the detection of the protocol: namely check if there exists an
x-forwarded-proto
, if it does, it's come from a http request, thus 301 to https. If one doesn't exist, assume it's https, don't redirect it (in practice I felt I might as well check to ensure the protocol was http before redirecting, but in the current set up I'm pretty sure that's the only scenario that can possibly occur).