For every other project, the requirement of using SSL/HTTPS crops up. And I’m sure, just like me, you were annoyed that there doesn’t seem to be a simple way to test your SSL stuff in your local development environment.
Well: Not any more. Here’s how you set up your local Rails environment so that you can use SSL in development if you want or need to.
Note: I’m assuming you don’t want to mess with your local Apache but want to use the regular Rails server command.
A Gist to Make Your Life Easier
Today, when I googled for solutions, I found a gist outlining how to set up a self-signed SSL certificate for your localhost. It works like a charm.
I’ve put all the files in \~/.ssl
so I can use it across
projects.
Configuring Your Rails App
Next up is Rails.
The first flaw: Using the regular script/rails server
seems
to be unable to serve both, SSL and non-SSL requests, at the same port –
which, of course, makes sense. We can circumvent this problem by simply
starting two servers at two different ports (I use the thin
webserver in this example):
thin start -p 3000
thin start -p 3001 --ssl --ssl-verify --ssl-key-file ~/.ssl/localhost.key --ssl-cert-file ~/.ssl/localhost.crt
Now we’ve got a non-SSL version of our app running on port 3000 and the
SSL version on port 3001. You can, of course, also put these in your
Procfile
if you’re using the awesome foreman
gem.
Now to the Rails app itself.
Since version 3.1, Rails ships with a controller macro named
force_ssl
so you don’t need the good old
ssl_requirement plugin any
longer.
However, the implementation of force_ssl
that ships with
Rails has a major flaw: It explicitly excludes the development
environment. And it assumes that the frontend server can handle ports
itself – which the regular Rails server can’t. Both issues can be
alleviated by monkeypatching the ActionController::ForceSSL
module that ships with Rails:
use_ssl and ssl_port are custom config settings that are not
part of the Rails standard configuration. However, in Rails 3 you can
simply add custom config settings by just defining
them. So just add
config.use_ssl = false
to
config/application.rb
and the same setting set to
true
in config/environments/development.rb
and
config/environments/production.rb
. In
config/environments/development.rb
, you also need to add
config.ssl_port = 3001
since this is what we defined
earlier. Note that I suggest turning SSL off again once you’re done
testing – constant port switching can be quite confusing (I know it does
confuse me).
And with that, you’re good to go. Simply add force_ssl
to
any controller you want to secure with SSL. If you navigate to the
non-SSL version of a page that forces SSL (e.g.
http://localhost:3000/some/page), your Rails app will automatically
redirect you to the SSL version (https://localhost:3001/some/page).
Note that depending on your browser you might receive a certificate warning because you’re using a self-signed certificate. Just tell your browser to shut up and go ahead with it.