Scroll down for setup instructions. Or, read this bit about SSL in the real world first.
SSL or Secure Socket Layer is a nice way to secure sensitive parts of your Rails application. It achieves to goals.
Firstly is encrypts all traffic between you and the remote server. Consider the passwords and personal information you submit to websites. When unencrypted (using HTTP), all this data is sent over the internet for all to read. With SSL (HTTPS) enabled, all traffic is encrypted, making it very hard for a third-party to eavesdrop.
Secondly, a proper SSL connection can give you trust in that you’re communicating with the right people.
For example, Rabobank (a Dutch bank) uses SSL for its website. When you open their site, you’ll notice the green ‘Rabobank Nederland’ in the address bar.
This tells me I am communicating with Rabobank Nederland. This is why SSL certificates are so expensive - the SSL authority needs to verify the identify of Rabobank before they issue the certificate.
In the example above Rabobank uses an EV SSL Certificate. EV stands for Extended Validation. This means that the SSL authority has verified (among other things) that Rabobank is a legitimate business and that they are the legal owner of the domain rabobank.nl
The cost for such an EV SSL Certificate is $200 - $1000 per year. You probably don’t need it for your site.
SSL for you and me#
When you are looking to secure the back-end of your site (where you login etc.), you only require the encryption part of SSL. There are two routes you can take
Self signed SSL#
You are able to create a working SSL certificate yourself. This will give you encryption, but no identity validation. When you use a self-signed SSL certificate all browsers will warn you about this.
- Encryption
- No validation
- Warnings from your browser
- Free
For me, that’s a reason not to use self signed SSL for any other than development and testing purposes.
Standard SSL#
Most SSL authorities provide you with a Standard SSL product. These certificates only check if you own the domainname. They also offer encryption and work (without warnings) in your browser. You can get one of these for as little as $9 a year.
- Encryption
- Domain validation / trust
- No warnings from your browser
- Cheap ($10 - $20)
Setting up SSL for your Rails application#
Setting up SSL is a web server thing. It does not involve your Rails appliation directly (but more on that in a moment).
If you followed my nginx+unicorn guide, you’ll have Nginx and Unicorn setup already.
Create your private SSL key (key)#
First you need to create a private key. Do this on you server. The following command will generate a 2048 bit key. When it asks you to set a passphrase, do so.
$ openssl genrsa -des3 -out example.com.key 2048
Generating RSA private key, 2048 bit long modulus
..................................+++
.................................................................................+++
e is 65537 (0x10001)
Enter pass phrase for example.com.key:
Verifying - Enter pass phrase for example.com.key:
Creating a key and Certificate Sign Request (csr)#
Okay, you now have your key. Next step, create the Certificate Sign Request. The sign request is the part you’ll send to the SSL authority to sign. You will need to provide some information here. Make sure you enter everything correctly.
Country Name
- Your 2 letter country code. I.e. NL, UK, BEState or Povince Name
. I.e. Noord-Brabant, New YorkLocality Name
- Your city. I.e. Eindhoven, LondonOrganization Name
- Your company or site name: Ariejan.net, Apple Inc.Organization Unit Name
- The section of your company. You may leave this blank. I.e. Online Services, FinanceCommon Name
- The domain this SSL certificate will be used for. If you want to run this on https://www.example.com, you enterwww.example.com
here. This is not a wildcard.example.com
will not work onwww.example.com
and vice versa.Email Address
,challenge password
andoptional company name
should normally be left blank. Just hit enter.
Here’s the full version:
$ openssl req -new -key example.com.key -out example.com.csr
Enter pass phrase for example.com.key: <<passphrase>>
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:NL
State or Province Name (full name) [Some-State]:Noord-Brabant
Locality Name (eg, city) []:Eindhoven
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Ariejan.net
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:example.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Great, you now have two files:
example.com.key
- your private key. Keep it secret, keep it safe!example.com.csr
- sign request
Get your certificate (crt)#
Now, go to your selected SSL authority, order your Standard SSL Certificate and upload the contents of example.com.csr
when requested.
After doing some validations, which may require you to click some links in emails, you’re certificate should be ready for download. Save this file as example.com.crt
.
Intermediate certificates#
Some SSL authorities work with so called intermediate certificates. This requires you to include an intermediate certificate with your own certificate. If your SSL provider requires this, save the intermediate certificate as intermediate.crt
.
For usage with nginx, you must place both your own and the intermediate certificates in a single file. This is easy:
cat example.com.crt intermediate.crt > sslchain.crt
Remove the passphrase from your key#
Now, this is not recommended, but many people do this. The reason is that when your private key has passphrase, your server requires that passphrase everytime your (re)start it. This could mean that your server cannot boot up without manual interaction from your part.
cp example.com.key example.com.key.orig
openssl rsa -in example.com.key.orig -out example.com.key
You now have example.com.key.orig
, which is your original private key with the passphrase. And you have example.com.key
, which is the same private key, but without the passphrase.
Setup nginx for SSL#
Finally, you can setup Nginx for SSL. Normally I add both a SSL and non-SSL configuration. Setup is very easy.
First of all, become root and copy your keys and certificate to /etc/ssl
.
cp example.com.key example.com.crt /etc/ssl
or if you use an intermediate certificate:
cp example.com.key sslchain.crt /etc/ssl
Next, you take your non-SSL server
configuration and duplicate it. Then you add the following lines.
listen 443; # Instead of Listen 80
ssl on;
ssl_certificate /etc/ssl/sslchain.crt; # or /etc/ssl/example.com.crt
ssl_certificate_key /etc/ssl/example.com.key;
location / {
# Add this to the location directive.
proxy_set_header X-Forwarded-Proto https;
}
Most of this is pretty straight forward. The proxy_set_header
directive is needed to let your Rails application know if the request came in over SSL or not. Normally this shouldn’t matter, but you’ll need it for the next part of this guide.
Save, restart nginx and your SSL connection should be available.
Automatically switch between SSL and non-SSL with Rails#
To take this site as an example, I don’t want to run the front-end through SSL. First of all, you can’t submit any data to my server. Second, I include several external resources (Disqus, Twitter, AdSense), that will give you warnings about using “insecure” content on an encrypted page.
What I do want is to encrypt traffic to the backend, where I log in and write posts like these.
I need to make sure that your browser knows exactly when and when not to switch to SSL. This is where the rack-ssl-enforcer
gem comes in.
First, update your Gemfile:
# Gemfile
gem 'rack-ssl-enforcer'
After you’ve run bundle install
, update config/application.rb
(or config/environments/production.rb
is you only want to configure this for your production environment).
# config/application.rb or config/environments/production.rb
config.middleware.use Rack::SslEnforcer,
:redirect_to => 'https://example.com', # For when behind a proxy, like nginx
:only => [/^\/admin\//, /^\/authors\//], # Force SSL on everything behind /admin and /authors
:strict => true # Force no-SSL for everything else
With the following statement, you achieve the following:
- When you access any URL with a path that starts with
/admin
or/authors
, you’ll be redirected to the SSL site. - Because we’re behind a proxy and want to do proper redirects, we specify the correct SSL domain.
- We set
strict
to true. If you access something that is not/admin
or/authors
, you will be redirected to the non-SSL version of that page.
There’s a lot more possible with the rack-ssl-enforcer gem. Checkout their README on Github for details.
Note: if you find yourself getting into an infinite redirect loop, make sure have the proxy_set_header
directive set correctly in your Nginx configuration.
Wrapping up#
You now know how you can setup an SSL certificate with Nginx and how you can make your Rails application automatically switch between SSL and non-SSL whenever you want to.