Free version available
Magnifying Glass

The PocketSmith Blog

Syndicated Posts

FaceBook

Twitter

Getting SSL working with rails, nginx, thin and Slicehost

Wednesday, October 1st, 2008 by James

As PocketSmith deals with confidential calculations and data, having the entire application run under a secure, encrypted connection has always been the intention. In a general sense, this means that the data transferred between the user’s machine and the application server can only be read by the user or the server. This going last night, and the below are my notes from getting everything running under a secure connection.

We have a virtual server with Slicehost, running the latest Ubuntu server (8.04) with the application being served with a Thin cluster on Nginx. The below is the process I went through to get everything going, both on our test virtual machine and beta production environment.

Server Setup

I was considering actually writing a post on this alone, but the relative ease of the setup does not warrant a separate post. The setup of the server used wholly the tutorials provided by Slicehost – they are awesome. I was completely fresh to Linux, however they were extremely straight-forward with specific commands in an easy to read format. Here they are in the order I followed them in when I set up the server about a month ago – follow this and any newbie will be able to nail it.

Getting SSL Going

1) Install OpenSLL

sudo aptitude install openssl

2) Choose a certificate provider

If you are just looking at getting SSL set up locally, you do not need to buy a certificate, there is a gem for the creation of a self-signed certificate. In this case I was setting up an actual certificate, however you can find instructions from Slicehost right here.

We decided to go with a GeoTrust certificate, because the prices were pretty sharp and the button is not as ugly as other alternatives. How shallow.

3) Follow these instructions here

These were the most descriptive but concise instructions that I found for generating the information required to get a certificate. I followed this up to the copying of the key / certificate.

http://docs.railsboxcar.com/Nginx_with_SSL

4) Get rails ready for SSL

Firstly, install the SSL requirement plugin. Go to your rails application directory, then give it a:

script/plugin install ssl_requirement

Then add the line

include SslRequirement

Into your app/controllers/application.rb file.

5) Decide what you want secure

You can add a simple line at the top of each individual controller to determine what actions you want to be secure, as described here: http://squeejee.com/articles/12-rails-nginx-and-ssl. However we wanted to make all pages in the application secure, so we added the following to app/controllers/application.rb.

def ssl_required?
  if ENV["RAILS_ENV"] == "production"
    true
  end
end

This then makes all pages require a secure connection, however only when the servers are started in the production environment.

6) Configure Nginx – /etc/nginx/sites-available/the.websiteurl.com

This is where things got a bit tricky for us, with the identical virtual machine and the live server behaving differently. What we needed to do however was to accept all connections over https, and redirect all attempted connections to http to the secure version. We already had a Nginx configuration file that we set up to respond to only one domain name (i.e. not both pocketsmith.com and www.pocketsmith.com), based on the Slicehost tutorial linked above.

Then through blending other tutorials we ended up with the following Nginx configuration (in /etc/nginx/sites-available/the.websiteurl.com). If you use the below, just replace anything bold.

upstream domain1 {
        server 127.0.0.1:3000;
        server 127.0.0.1:3001;
    }

server {
    listen               80;
    rewrite ^(.*)        https://the.websiteurl.com$1 redirect;
}

server {
            listen   443;
	    ssl on;

	    ssl_certificate /usr/local/nginx/certs/cert-name-goes-here.crt;
	    ssl_certificate_key /usr/local/nginx/certs/key-name-goes-here.key;

            server_name the.websiteurl.com;

            access_log /home/username/path_to_application_folder/log/access.log;
            error_log /home/username/path_to_application_folder/log/error.log;

            root   /home/username/path_to_application_folder/public/;
            index  index.html;

            location / {
			  proxy_set_header X_FORWARDED_PROTO https;

                          proxy_set_header  X-Real-IP  $remote_addr;
                          proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
                          proxy_set_header Host $http_host;
                          proxy_redirect false;

                          if (-f $request_filename/index.html) {
                                           rewrite (.*) $1/index.html break;
                          }

                          if (-f $request_filename.html) {
                                           rewrite (.*) $1.html break;
                          }

                          if (!-f $request_filename) {
                                           proxy_pass http://domain1;
                                           break;
                          }

            }
}

Note that we are listening on port 80 right at the top of the file, and performing a redirect to the secure version of the page. This took way to long for me to work out.

7) Panic and flee to your business partners house

So just as you are about to save this critical file and making a time-critical change on your live server, you can expect that your internet connection will drop and won’t come back. This means you quickly leave, get to an internet connection and hope that everything hasn’t melted. Nothing like compounding the intensity of the situation heh.

8 ) Battle with inexplicable differences between staging and production servers

The configuration that worked above on the staging server simply broke when put on the identical production server. The user was not being redirected from the insecure connection to the secure one, with the port 80 configuration – it appeared that Nginx was using the default configuration instead of the.websiteurl.com. The quick and dirty fix was to comment everything in the default configuration out, and put the port 80 server into the default. Although this does mean that we are up, secure and able to move onto other pressing things, I need to look further into what the cause for this discrepancy between staging and live is.

Despite the hiccups, we are running everything over a secure connection with no issues. Success!

Tags:

2 Responses to “Getting SSL working with rails, nginx, thin and Slicehost”

  1. Glenn says:

    If you’re using Thin, you can connect via a unix socket and remove the additional TCP overhead between nginx/thin/mongrel:

    http://rubypond.com/articles/2008/02/06/improving-rails-app-and-mongrel-performance-with-thin/

  2. James says:

    Awesome Glenn, thanks for reading and for the heads-up, will look into this now.

Leave a Reply