Rails comes with a built-in support for SSL in form of config.force_ssl. But what does it exactly do?
SSL middleware
The force_ssl directive adds the ActionDispatch::SSL middleware layer which is a Rack middleware for HTTPS requests:
# rails/railties/lib/rails/application/default_middleware_stack.rb
...
def build_stack
ActionDispatch::MiddlewareStack.new.tap do |middleware|
if config.force_ssl
middleware.use ::ActionDispatch::SSL, config.ssl_options
end
...
This middleware does two main things:
-
SSL/TLS redirect: Redirecting
httprequests tohttpswith the same URL host and path. Both from the Rails server and the browser by requesting HSTS. -
Secure cookies: Setting the secure flag on cookies so browsers don’t send out any cookies for plain
httprequests.
Configuration
The config.force_ssl directive can be set per environment in config/environments/[ENVIRONMENT].rb.
We can adjust the SSL settings with two options, ssl_options and assume_ssl.
The ssl_options directive configures the ActionDispatch::AssumeSSL middleware. We can use it to redirect to a particular host:
config.ssl_options = { redirect: { host: "secure.widgets.com", port: 8080 }
Or exclude healthcheck path from the HTTPS redirect:
config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } }
The config.assume_ssl adds additional ActionDispatch::AssumeSSL middleware that will set the following HTTPS headers:
HTTPStoonHTTP_X_FORWARDED_PORTto443HTTP_X_FORWARDED_PROTOtohttpsrack.url_schemetohttps
This is useful when running Rails with force_ssl but behind a load balancer or proxy that terminates SSL connection. This prevents ActionDispatch::SSL auto-redirect to HTTPS.
Get Test Driving Rails and make your tests faster and easier to maintain.
