Ultimate Guide to Setup SSL on Rails and Apache 2 (with Ubuntu seasoning)

UPDATE 5/24/08: There was a recent APB security bulletin for all those running Debian-based OSes (including Debian) with OpenSSL 0.9.8c (released 2006) onward. You can read about it here. Long story short: if you’re running a flavor of Debian, you should run “sudo apt-get update” before you start these instructions, to ensure that you’re using the patched version of SSL. And now back to your regularly scheduled programming

For something that a million billion web sites have to do, the state of documentation on how to get your Rails app running with SSL in a standard Apache configuration, is.. how shall we say it.. ass. Even the previously lauded “Advanced Rails Recipes” only scratches the surface on what it really takes to get a Rails app running with SSL. This post will aim to change that with a (relatively) comprehensive, front-to-back guide of what I learned in setting up our app with SSL over the last couple days. Maybe it isn’t really the “ultimate” guide, per se, but let’s say we’re speaking relatively here.

Step 1: Understand as little as possible about what SSL is and how it works.

SSL is the technology that’s working when your browser visits an https:// address. It is typically used by production websites for logging in, updating user data, and of course, submitting top secret data. The point of SSL is to encrypt sensitive user information so that it isn’t sent across the web in plain text form, where it could be read and used maliciously by evil pimpled pirates.

To setup an SSL connection, you need to create a key and certificate. You then need to get that certificate endorsed by a “certificate authority” (henceforth, a CArtel… more on the name in a minute). For testing purposes, that CArtel can be your website, but if you endorse your own certificate, visiting users will be asked if they want to trust your site as a certificate authority before proceeding to your https:// pages. So real production sites rely on the syndicate CArtels. The biggest CArtels include Verisign, Geotrust, Thawte, and GoDaddy. Generally speaking, the bigger the CArtel, the more they charge you for the same service. Like the Corleone family. In the process of setting up your SSL, you will quickly learn to despise all of the above CArtels for a variety of reasons, most obviously because they charge ridiculous amounts ($20-$500 yearly for the most basic certificate, $1500+ for an EV one) for a trivial service, and despite that exorbitant cost, all three that I tried were broken to varying degrees and a pain in the ass.

Where was I? Oh yes, SSL. An ultimate guide to it.

Step 2: Generating your SSL key and Certificate Signing Request

Before you can enjoy engaging with your CArtel of choice, you must generate an SSL key and a Certificate Signing Request (CSR). The SSL key is used 1) to generate your CSR and 2) by Apache, to compare against the certificate given to you by your CArtel. All the CSR is is a plain text file that has a big hex string you’ll submit to the CArtel when you’re ready.

The process of creating the key and subsequent CSR varies per operating system. My OS is Gutsy Ubuntu, so if you’re running that (or later versions), you’re in luck, cuz I’ve got some explicit instructions ready for you without leaving the comfort of this blog. If you’re not, these instructions may still work with other versions of Linux, but I don’t know what you do in Windows (seriously, Windows? We’re talking about a Rails stack, aren’t we?).

1. Generate a key
In any directory, run “sudo openssl genrsa -des3 -out your_website_name.key 1024 or “sudo openssl genrsa -out your_website_name.key 1024″

The difference between the first and second command: the first one generates your key in such a way that it will require a password to be entered every time it is read (= every time Apache starts). It is possible to run a program to output this passphrase (Google “SSLPassPhraseDialog“), so you can still start Apache automatically on system reboot, but various websites I read suggested that using one of these programs is generally no more secure than just generating a key without a passphrase (which is the second option). Which you choose depends on whether you can have someone around your server whenever it needs rebooting, and how paranoid you are that someone will be able to log onto your box and steal your key (meaning that their porn site is now indistinguishable from your web site (at least from the standpoint of the the CArtel)).

If you’re running a version of Ubuntu that doesn’t already have SSL installed, you should just be able to install it with “sudo apt-get install openssl”

2. Create a CSR
In the directory that you created your key, run: openssl req -new -key your_website_name.key -out your_website_name.csr

And that’s that.

Step 3: Pick a CArtel, any CArtel! They got stuff you need, and they know it.

Here’s where you get to decide if you want to pay $500 for a mediocre service (Verisign), $20 for a pitiful one (GoDaddy), or something in between for a broken one (GeoTrust, $250). I tried all three of those. My brief summary is thus: Verisign is the biggest name in CArtels, and they charge like it. You can get the exact same certificate VeriSign charges $500 for at GoDaddy for $20. I started setting up a trial certificate at Verisign, but gave up when I realized that they were going to remind every user on my site that our certificate was a trial one until we forked over the $500. I suppose that maybe $500 is worth it for some sites, since you get to put their flashy Verisign logo at the bottom of your SSL pages, but I couldn’t bring myself to subsidize the pork. It feels too much like the Title Insurance company that charges me $1000 when I buy a house for them to run a query in their database.

I actually signed up for a GoDaddy certificate. Their interface is esoteric, clearly designed by an unfed engineer who needed to get home in time for his WoW mission. But, after signing up, then waiting about a day while they verified something-or-other, the GoDaddy certificate worked. It did require a small extra step of download an “intermediate certificate” in addition to my signed certificate, but for the price, it was alright.

GeoTrust simply annoys me. I’ve gone through their signup process twice, and been rejected by their phone verification system as many times. Luckily, that verification system seems to be “just for fun,” because, despite failing that mandatory step, they still mailed me a certificate. Their UI is similarly awful to GoDaddy, and their site appears to be unmanned (clicking on the “login with certificate” button gives a fatal certificate error). But they work, and their logo is fairly well recognized.

I didn’t spend too much time on Thawte or Comodo, but I can’t imagine they’d be much worse than the above.

The ultimate reward for powering through the CArtel process is that they mail you a long string that you paste into a .csr file. In our case, I pasted the certificate given to me by our CArtel into a file I created and named “bonanzle.csr”.

Step 4: Copy the key and CSR files + setup your Apache config file (aka: the hard part)

In Gutsy with Apache2, the recommendation given by this helpful page is to copy your files as follows:

sudo cp your_server_name.crt /etc/ssl/certs

sudo cp your_server_name.key /etc/ssl/private

Where “your_server_name.crt = the file you created in the last step” and “your_server_name.key = the file you created in step 2.1”.

Next, you’ll need to make sure you have the Apache “SSL” mod enabled (for SSL, duh), and the “headers” mod enabled (for Rails to recognize the SSL). In Apache2, this is accomplished by running “sudo a2enmod ssl” and “sudo a2enmod headers”. I did in the Apache directory (/etc/apache2), but I’m not sure if that mattered.

Finally, you setup your Apache config file. I think this could probably be put equally well in either /etc/apache2/apache2.conf, /etc/apache2/httpd.conf, or /etc/apache2/sites-available/default. All of those files are run on Apache startup. I chose the last of those, because it was recommended by the Ubuntu Gutsy SSL setup page (probably just for separation sake). Here was what I added to my /etc/apache2/sites-available/default file:

<VirtualHost *:443>

# SSL requests should proxy just like normal ones... this is the same
# code I use in my "VirtualHost *:80" block to forward http requests
# to my mongrel cluster... If you have different proxying code,
# you'd paste that here.

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]
RewriteRule ^/$ /index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]

RewriteRule ^/(.*)$ balancer://railsapp%{REQUEST_URI} [P,QSA,L]

# The actual SSL stuff, make sure the engine is on, enable some options that the Gutsy page said I should,

# and tell Apache where my key+CSR files are
SSLEngine on
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
SSLCertificateFile /etc/ssl/certs/bonanzle.crt
SSLCertificateKeyFile /etc/ssl/private/bonanzle.key

# Used by Rails. Mentioned in all the Rails SSL tutorials.
RequestHeader set X_FORWARDED_PROTO "https"

Depending on your CArtel, you may also need to ensure that your ServerName and ServerAlias match the “common name” field that you specified. I know I had to do this. This was accomplished by adding the following lines inside my <VirtualHost *:80> block (I did it at the top, but that almost certainly doesn’t matter):

ServerName www.bonanzle.com
ServerAlias www.bonanzle.com

After that, save the file, reload Apache and cross your fingers. If you Apache restarts sucessfully, you have completed the most difficult part of the process! If not, visit /var/log/apache2/error.log and get to Googling.

Step 5: Setup Rails with SSL (aka the easy part)

Here’s the part you can find in many existing Rails tutorials that copy/paste the README in the ssl_requirement plugin. Firstly, you install the ssl_requirement plugin (“ruby script/plugin install ssl_requirement”). Then, add near the top of your application controller the line “include SslRequirement”. Then add the following block to your application controller, so your development server will continue working:

def ssl_required?
return false if local_request? || RAILS_ENV == 'test'

Then, any action that should go through SSL just needs to have a line added in its controller, “ssl_required :action_name”. You can also do “ssl_allowed :action_name” if the action can be used either way.

You should probably also know…
Most CArtels will only validate one domain (validating two domains would mean an extra query for their database) for your X hundred dollars, so you need to make sure that all actions that will be SSL can only go through one address. Specifically, you need to make sure that any possible subdomains will map to one address if you don’t want to buy multiple certificates. You’re probably already doing this if you have a production site, because if you allowed stunts like “bonanzle.com” and “www.bonanzle.com”, then users sessions could also be messed up. However, if you haven’t yet setup a redirect from subdomainless URLs to www.* URLs, here’s the code I used to do it:

# Redirect all bonanzle.com/ request sto www.bonanzle.com
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^bonanzle\.com
RewriteRule ^(.*)$ http://www.bonanzle.com$1 [R=301,L]

Hopefully this ultimate guide will save you minutes or hours relative to Googling a bajillion sites to put all this data together. Leave a comment if you’ve gone through this and found it to work or not work. I’d also be curious if any else has experienced a CArtel that they would recommend (e.g., one where a UI-minded person or SSL novice go through signup process and not gasp in horror). Thanks for any feedback.

11 Replies to “Ultimate Guide to Setup SSL on Rails and Apache 2 (with Ubuntu seasoning)”

  1. Hi,

    First, thanks for the great tutorial 🙂

    I’ve found a litlte big on the tutorial code, the line that is:

    openssl req -new -key your_website_name.key -out your_website_name.csr

    Should be:

    openssl req -new -key your_website_name.key -out your_website_name.crt

  2. Hey Mauricio! Thanks for your comment.

    How do you figure that it is wrong? The CSR is the file that you submit to your CArtel. A CRT file is an actual certificate file, basically, the response to the CSR file. You can generate this yourself (called a “self-signed certificate”, generated with something like “openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt”), but if you make it yourself, then any user to your site will be prompted about whether to accept you as a CA.

    Do you have some more details about what led you to get better results with the crt extension?

  3. Great article, it helped a lot to understand how SSL works with Rails. However I got stuck at the point where I install the ssl_requiremnt plug in and a couple of ssl_required, and I restart the server. Then I am getting this error:

    NameError in ProjectsController#index
    uninitialized constant SslRequirement::UserSystem

    I have searched for this error, no luck. I notice that the plugin is correctly installed in the vendors directory. As soon as I remove the line “include SslRequirement”, my site works again.

    What am I doing wrong??

    Thanks again!

  4. That did the trick. I also received the SslRequirement error, but it went away once I had restarted my mongrel cluster.

    I used Entrust. I was quite impressed with their customer service and technical support. They were more thorough in their checking of the company identity than I have experienced in the past, but I would rather have a real person call me and discuss than having to talk with some IVR.

    Thanks for a great article. I was spinning my wheels for some time.

  5. Sorry I’m two years too late with this helpful tidbit — anyone buying a cert should seriously look at Comodo. Their signup processes are not terrible and their prices are very low (lowest maybe). The secret is, if you want a cheap cert you go to their InstantSSL.com site instead of the main site, and if you want a really, REALLY cheap cert you go to their PositiveSSL.com site, which is so cheap they don’t even advertise it on their main site, and get one for something like $10/year. Yes, $10! That’s not the sort of cert you want for an e-commerce site though, so if you are doing e-commerce or very sensitive information you need to read up on their beefier certs.

  6. For completely free certificates without warnings, try http://www.startssl.com/?app=1
    This was the only non-CArtel CA I could find.

    It’s kind of awkward to set up, but not much more than GoDaddy.
    I’ve just set up both, and at least with StartSSL it’s free and you don’t get bombarded with awful GoDaddy advertising.

    Also, I don’t think it’s necessary to redirect people to http://www.yourdomain.com since the SSL certificates work on both https://www.yourdomain.com and https://yourdomain.com. Then all you have to do is change your cookies by adding this to production.rb:

    ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(:session_domain => “.yourdomain.com”)

    That means your sessions work on all subdomains.

Leave a Reply

Your email address will not be published. Required fields are marked *