AWS: Ruby on Rails Deployment Part 2: Ruby, RubyGems, Rails, Thin and Nginx

The previous article in this series has left us with a minimally-configured Nginx installation running on an EBS-backed Ubuntu EC2 instance.

This article will pick up where we left off. The latest versions of Ruby and RubyGems will be downloaded and installed. Then the Rails and Thin gems will be installed. Nginx will then have the final configuration changes applied to enable it to proxy through to the Thin workers. Thin is a lean Ruby-based web-server that has been designed to replace Mongrel (which was the standard Ruby web server until development ceased), and uses various components lifted from Mongrel (e.g. the parser - giving us the same (or better?) speed and security as Mongrel).

It’s been a while since I deployed Ruby on Rails - and that was using Mongrel - so let’s see how Thin matches up.

libyaml

Make sure you have installed libyaml and the appropriate development files (headers, etc.) prior to compiling and installing. Forgetting this will result in a big facepalm and things like:

To fix this, install libyaml and reinstall your ruby like the good warning above. On Ubuntu, I installed libyaml-0-2 and libyaml-dev

and reinstalled my ruby as per the following procedure. If you need other specific functionality, install any prerequisites (gdbm, curses, readline, Ruby/Tk, etc.) now, prior to compiling Ruby. For example, I already had libssl1.0.0 and libssl-dev installed, so SSL support was automatically configured and compiled in.

I’ll also install libsqlite3-dev here as Rails depends on it.

Ruby Installation

Ruby will be installed from source so the latest features and security patches are included (and, perhaps, the latest bugs). The most recent available stable version at the time of writing is 1.9.3-p385. The tarball has been placed in /usr/local/src - extract it:

Next, configure Ruby. I’ll be installing with a --prefix of /usr/local. Once configure has been successfully executed, compile and install Ruby.

Ruby is now installed - fire it up interactively and test that it works. You can run Ruby interactively with the irb interpreter:

Good - Ruby is done.

RubyGems Installation

The latest RubyGems download available to me now is 1.8.25. I downloaded to /usr/local/src and extracted:

Install RubyGems:

Observe any error messages, and note any warnings. Also note the following:

The gem command will be used to install gems, i.e. Rails and Thin in our case.

Gem Installation

Two gems are required: the rails framework and the Thin Ruby web server. Install rails:

You’ll see any gem dependencies fulfilled and installed prior to rails itself. The gem command is Ruby’s answer to PHP’s pear and Perl’s cpan.

At this point I decided to check that the Rails installation was successful. I ran into an issue which I’ll describe here, and provide the solution for. First, I created a temporary directory:

I then created a new Rails application called test1:

When I attempted to start the WEBrick-based Rails server, I received the following error:

To fix this, I installed the therubyracer gem and its dependencies:

Next, I modified my Rails project’s Gemfile and uncommented the following line:

The Rails server now started as expected.

Now that’s working, install Thin and its dependencies:

Using the same Rails project I just created, I verified the Thin installation as follows:

Uh-oh! Whoops, I forgot to add thin to my Gemfile. Adding the following line

fixed the issue.

With the gems all installed and tested, you can now cease further Ruby-related tasks as root. Rails projects can be created by any user, in their appropriately-owned directories.

Rails Deployment Preparation

I’ll create a deploy user. I’ll use this user to create Rails applications, or to deploy them to an appropriate location, and to run the Thin instances. I’ll use /var/www/sitename/<railsapp> to serve my applications. For now, create the deploy user with /var/www as their home directory.

Add the following to /etc/sudoers:

And set appropriate permissions over /var/www:

Rails Deployment

Let’s create our base directory - working as the deploy user:

Change directory, and create the Rails application superfoo:

Enter your password at the following prompt (this will use sudo to install the bundle).

Modify your Gemfile

and ensure the following lines are present:

Start thin in the foreground and ensure that all is well:

Hit Ctrl-C - now we’ll create our Thin cluster.

NOTE

Using ruby-1.9.3-p448, rubygems-2.0.3 and rails 4.0.0 required a lot more sudo configuration to work correctly. First, a permissions and ownership change:

Then the /etc/sudoers rules in full:

With these in place, a rails deployment as the deploy user (using the aforementioned software versions) should work.

Configuring a Thin Cluster

For Production purposes, never run a single Thin instance. Much like Mongrel, we can run up two or three Thin workers to handle our requests and server our Rails applications. The Thin usage documentation is very clear so have a read of that alongside this article.

From within our Rails project directory, I’ll generate a configuration file (superfoo.yaml) by starting Thin in config mode:

Here, I configure Thin to start 3 servers, starting at port 8000 (so - 800{0,1,2} will be used by our three workers), and writing the configuration out to superfoo.yml.

Now, I can start the Thin cluster using the YAML configuration file:

And stop it:

You should configure your system startup scripts (upstart, init.d scripts, SMF, whatever) to automatically start Thin, and to do so prior to Nginx coming online.

You can check that Thin is correctly serving your application by running:

If you’ve stopped Thin, start it up and leave it running. The final step is to complete our Nginx configuration.

Nginx Configuration

If you recall from the first article, I created the directory /etc/nginx/vhosts.d to hold my virtual host configuration files. An include statement in /etc/nginx/nginx.conf is used to include any *.conf files under this directory. This enables me to disable a virtual host by doing something like

and disable a virtual host. It is obvious that it’s just as simple to enable a virtual host.

Nginx is a feature-rich web server, and can be used to serve static content to save Thin from having to do so. Nginx is often used in this way, serving static content and proxying other requests through to application servers (or other web servers such as Thin) for dynamic content to be served.

We don’t have any static content to serve (but could easily configure Nginx with the appropriate location stanzas to serve it directly - see the documentation) so the following is what my /etc/nginx/vhosts.d/00_www.example.com.conf file looks like:

Again, commented so as to be self-explanatory. Run a configuration test, and if happy, reload Nginx:

You should now be able to hit the Ruby on Rails application you created as follows:

(or if this the only virtual host configured on the server, hit http://localhost). You should see the Ruby on Rails welcome page appear.

Well done - it’s all working!

Conclusion

This two part series has guided you through the installation of Nginx, Ruby, RubyGems, Rails and Thin - all of the various components for a high-performing Ruby on Rails installation on an Amazon EC2 Ubuntu instance.

Various configuration concepts have been introduced, especially around Nginx and virtual hosts.

You can read more about Nginx on the project website.