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
http
requests tohttps
with 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
http
requests.
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:
HTTPS
toon
HTTP_X_FORWARDED_PORT
to443
HTTP_X_FORWARDED_PROTO
tohttps
rack.url_scheme
tohttps
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 while it's in prerelease.