Deploying a Rails Application

Deploying a PHP web application involves either uploading files to a server via FTP, or committing and pushing to a master branch of a Git repository. There is nothing complex about it. Deploying a Rails app is easy according to the official Rails documentation. As much as I love the official docs, they have got that part badly wrong. Deploying a Rails app can be a massive headache, not least because there are so many options.

In the end though, it boils down to two things: you can either deploy to a cloud based service where most of the hard stuff is looked after for you, or for more control, you can deploy to a Virtual Private Server (VPS). We’ll take a look at both options in this series.

Deploying to the Cloud

We’ll choose Heroku as our cloud option, since it is very popular for Rack and Rails app deployments. You deploy to Heroku by pushing your changes to the Git remote that Heroku provide for you when you first create the app on their service.

It should feel familiar for PHP coders transferring to ruby, especially if you have used a cloud platform like phpfog for example.

There are several steps involved in getting your Rails app up and running on Heroku:

  1. Develop your app (doh!)
  2. Sign up for Heroku if you haven’t already
  3. Initialise Git for your project
  4. Create a Heroku app
  5. Add the Git remote for Heroku (you might already have a Github remote repo for example)
  6. Push your app to Heroku
  7. Migrate the database (if you are using one)

Choosing a Database

Heroku doesn’t support Sqlite, so if your app uses it, Heroku will complain. Heroku uses the excellent Postgresql. During the initial deployment of your app, you can run your migrations to populate your Heroku Postgresql database. If you have moved to developing with Rails from PHP, you’ll be used to MySQL. In which case, you have nothing to fear from Postgresql. It has gained in popularity with Rails developers recently, so it is well worth getting used to.

If you are still considering using Sqlite, this article on the Heroku dev center should put things into perspective for you.

Making a Start…

So, your app is at a point where it can be pushed to Heroku. Turning it into a Heroku app is just a case of getting on the command line/terminal. Change directory to your project, and make sure you have committed all your latest changes. Then simply do:

heroku create 

The next thing that will happen is Heroku will respond by telling you your app has been created. It is highly likely that it will have an odd name (infinite-escarpment-4759 for example), but we can change that shortly. You will also be told what your Git remote url is for Heroku. The nice thing about that is, you can push your changes to Github for example, and then, when you are ready to deploy, you can push to your Heroku branch.

Changing the App Name

Assuming you want this app to have a real purpose rather than just for testing, you’ll want to use a sensible name for it. Back on the command line do:

heroku apps:rename new_name_here 

The nice thing about this is that your Git remote will automatically be updated. If you use the Heroku web site to rename your app, you’ll need to remove the old Heroku remote and add the new one:

git remote rm heroku git remote add heroku git@heroku.com:newname.git 

If you have a domain name that you want to use for your app, return to the command line and do:

heroku domains:add www.mydomain.com 

Next, we’ll deploy.

Deploying the App

All you need to do is:

 git push heroku master 

You’ll see Heroku run through a whole bunch of processes, including rake assets:precompile which is really nice. When it finishes, you should see something like: http://yourapp.herokuapp.com deployed to Heroku. Great! Oh, wait a minute though…

The Database

You can also deploy your migrations. Back on the command line do:

heroku run rake db:migrate 

you might see a deprecation warning about the plugins in vendor/plugins. You can safely ignore the warning if you know you haven’t done anything with plugins.

That’s All Folks…

Really. That’s it, your app should now be up and running. The only problem with Heroku is: the free version is a great service. However, if you need to add more resources, it can get quite expensive. Don’t say I didn’t warn you…

Deploying to a Virtual Private Server (VPS)

The other option is to buy yourself a VPS, and deploy your app to that. The one I’m using here is called Linode. The first thing I should point out is that, if setting up servers doesn’t appeal to you, then choose Heroku.

When you sign up with Linode, you can choose the (Linux) server operating system. They have Ubuntu, Fedora, OpenSUSE etc. so your favourite will probably be supported. It is also possible to create and tear down if you go wrong. In fact, it’s encouraged on Linode. So if you are a Linux n00b, there is plenty of help and support.

When your server is set up it is a raw, basic server installation. That means, to get a Rails app up and running you will need to do some installing first. Oh, and in case you were wondering, no, there isn’t a GUI. It’s command line all the way.

The Production Stack

You have options here. I ended up going with Nginx for a web server, PostgreSQL for database stuff, and rbenv to manage Ruby versions. You could just as easily choose Apache, Phusion Passenger, and MySQL. I made these choices because I had already tinkered with Phusion Passenger and RVM, and wanted to try the other options.

Once you have your Linode set up, login in via SSH. Your Linode dashboard has all the information you need to do that:

ssh root@176.xxx.xxx.xxx 

You should run a distro update and install any that are required first. Then install the production stack components. If you are using ubuntu install the software properties option to make it easy to add new repositories to apt:

apt-get -y install curl git-core python-software-properties 

Then you can add the stable branch for Nginx:

add-apt-repository ppa:nginx/stable 

Regardless of your distro you need to install:

  1. Nginx or Apache
  2. MySQL or PostgreSQL
  3. Also install node.js while you are at it, so that you have a way to execute Javascript.
  4. You will need to install Git and Curl too.

Installing Ruby via rbenv is easier if you use the installer script:
curl -L https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash

You’ll be told to copy some lines into your .bashrc file, so make sure that you do. Where you copy them is a bit of a gotcha too. The lines need to go above this line in your .bashrc file:

# If not running interactively, don't do anything [ -z "$PS1" ] && return 

This is so that rbenv will work with Capistrano deployments, which we’ll get to shortly. You’ll need to reload your .bashrc file now: ~/.bashrc. At this point the rbenv command will be available on the command line, and can be used to install some important dependencies for Ruby. For example, for Ubuntu 12.04 you can do:

rbenv bootstrap-ubuntu-12-04 

Then wait for a while as the dependancies are installed. Once that is done, you can install Ruby:

rbenv install 1.9.3-p125 

And then set it as the default Ruby:

rbenv global 1.9.3-p125 

Finally, install the bundler gem so that we have the required access to the bundle executable:

gem install bundler --no-ri --no-rdoc 

Use the rbenv rehash command to pick up the changes:

rbenv rehash 

Getting the Application Ready

Assuming that you will manage your source code through Github, it’s a good idea to add an ssh connection to it from our server. While still logged in, do: ssh git@github.com. This will ensure that when we deploy via Capistrano, we shouldn’t get any “unknown” errors.

The idea is, that before we deploy via Capistrano we can check that everything is committed to Github first.

Now you can develop and push to github as normal; your Linode server is nearly ready to recieve the deployed app. First though, we need to set up Unicorn and Capistrano.

Unicorn and Capistrano

Unicorn is a HTTP server that works nicely with Nginx for running Rack applications. Capistrano is one of the many ways to deploy a Rails app in a semi-automated way.

We will need to add both of them to our gemfile:

gem 'unicorn' gem 'capistrano' 

Back on the command line, in your application directory run the capify command. That will create a Capfile and a config/deploy.rb file, both of which, will need to be edited.

Starting with the capfile, we are using the asset pipeline so we’ll uncomment accordingly:

load 'deploy' # Uncomment if you are using Rails' asset pipeline load 'deploy/assets' Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } load 'config/deploy' # remove this line to skip loading any of the default tasks 

Then, we can paste in our Capistrano recipe:

It’s beyond the scope of this article to go through the file in detail. However, you can see that there is a section for setting up roles for the web app and the database, and also, the directory that the app will be deployed to.

Our Github credentials are included, and there is a section for making sure all local changes have been committed before the deployment runs.

We also need to add a config file for Nginx in: config/nginx.conf:

This is a standard config file for Nginx that maps to the location of your app. You can find sample nginx config files here.

You will also need to add a config file for configuring Unicorn:

You can see a sample file here, but the file basically sets paths and the number of worker processes. This file also goes in your app’s config directory.

The final config file we need to add to our application is a shell script to start Unicorn:

Again this goes in your app’s config directory. It is a fairly generic script with variables that will need to be adjusted at the top of the file. This script will also need to be marked as executable.

It is a good idea to set up another user on your VPS, so that user’s credentials are used rather than root, for the user that appears in the various config files.

You should commit the config files to your Git repository too.

Running the Deployment

Now you can run: cap deploy:setup to begin deploying the application. the command will log into the server using the user account you set up. It will also create the various directories specified in your config files.

You should now be able to run: cap deploy:cold. The ‘cold’ option means the database migrations will also be run. You may see errors at this point, but the output will give you an indication as to where the problem is so it can be fixed.

Fixing Nginx Default Site

When you visit your server’s IP address, you’ll still see the default Nginx page. Log in to your server via SSH, and remove the symbolic link:

sudo rm /etc/nginx/sites-enabled/default 

Then restart Nginx (this is for Ubuntu, your distro’s documentation will help you with this):

sudo service nginx restart 

One More Thing…

Run the following command so that Unicorn starts properly when the server is restarted:

sudo update-rc.d unicorn_appname defaults 

You should now be able to browse to your site and see your app running.

Finally…

The fastest and most pain free way to deploy a Rails app is via Heroku, there is no doubt about that. However, it can get expensive, and you don’t have finite control over your application. For as little as $20 per month, you can have a full featured, virtual private server to configure your own way and with maximum control over the apps you deploy. It is a much more involved process though.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Tsega

    Whew! You know as much as I love doing rails applications, I loath deployment part except on Heroku that is.

    This article was something I have been looking for for weeks, although what I need right now is deploying on a VPS with Apache and Passenger. Do you have any resource on that?

    Thanks.

  • http://sj26.com Samuel Cochran

    I recently wrote up an Ubuntu vps setup which allows Heroku–style git deployments which may interest you:

    http://sj26.com/2012/10/02/paas-ish-ubuntu