Ssl – Running Rails3 with force_ssl = true, with nginx, on AWS EC2 with SSL terminated by an ELB, setting up health check

amazon-web-servicesruby-on-railsssl

I want to run my entire Rails app with SSL, so I thought to use Rails' global force_ssl config option, which works great, except that the ELB's healthchecker will never work because if I set it to http, Rails will forward to https with a 301, and the health check will fail since it is not 200. If I set it to https, nginx/rails will be unable to handle the request, since SSL is handled by the ELB and nginx/rails is only handling HTTP.

My non-ideal solution would be to make an exception to the global force_ssl just for the health check page, but Rails' global force_ssl config always overrides the force_ssl :except => :health_check so that doesn't seem to work.

Another solution would be to not use ELB for SSL termination, and set up HAProxy or so, but I want to use Amazon's infrastructure as much as possible for things, to focus more on core development of the project instead of infrastructure.

This is my first serverfault post, so I appreciate any help I can get (or more information I can give). Thanks.

Update:

So far I "resolved" this by having the ELB access the EC2 instance over a different port than 80 that only it can access, which feels extreme, but keeps a separation between the application and server layers. If the healthcheck request comes from the ELB from this port, nginx will forward the X-Forwarded-Proto header set to 'https' which will let Rack think that it came over SSL, and let it through. For all other traffic coming in across the standard port 80, it just forwards the X-Forwarded-Proto header given by the ELB, which will accurately report what the external user was using, and let Rails decide to force https or not depending.

Still awaiting a cleaner solution, but this is what I have.

Best Answer

6 months later, here is your cleaner solution.

# config/environments/production.rb
config.ssl_options = { exclude: proc { |env| env['PATH_INFO'].start_with?('/health_check') } }