Reputation: 8827
My ruby on Rails application is configured with the following:
config.force_ssl = true
And I set up the following elastic load balancer:
With this configuration everything works, but I do not understand why? with the code above, my application instance will return a 301 redirect in response to HTTP request. When the HTTP request is handled by the load balancer, it is forwarded on to to the instance as a HTTP request. Shouldn't this result in another 301, and therefore an endless loop?
Upvotes: 1
Views: 883
Reputation: 1036
EDIT I thought a bit about my answer and decided to get in to some more detail with it.
Network communication is usually composed of several layers, among which are the physical layer, which is the cable/radio channel where information travels through, the transport layer which is often TCP/IP, the protocol layer which in our case is usually HTTP or HTTPS and finally the application layer which is what our rails app handles.
Rails usually never gets in touch with the actual HTTPS data stream, as this is handled by your webserver. So how does force_ssl work at all?
The protocol layer is handled by the webserver (nginx, mongrel...) and this is who could care first about forcing ssl. When the webserver hands over a request to the application layer (hence, the rails app), it also provides a lot of meta data, which includes requester IP, request path, request format, a lot of header variables and also information about the used protocol.
When a request arrives at your webserver on port 443 (and uses HTTPS protocol), the webserver sets the header flag SERVER_PROTOCOL
to https
.
If a proxy server (like load balancer is) receives a request on 443 and forwards it to 80, it adds the X-FORWARDED-PROTO=https
header to the request, which is made available for your rails app by the webserver.
Now, long story short: config.force_ssl
requires SERVER_PROTOCOL
OR X-FORWARDED-PROTO
to denote https
.
ORIGINAL ANSWER The rails force_ssl method does not really force a request to arrive on port 443 on your server, it is satisfied when the original (client) request was sent over ssl through the internet. The load balancer (as a proxy) sets the header X-FORWARDED-PROTO to "https". rails trusts that information and that is why this is working.
More info on that can be found in the elastic load balancer docs: http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/TerminologyandKeyConcepts.html#x-forwarded-for
Upvotes: 3