蓝天,小湖,湖水中一方小筑

Deploy RoR application with Nginx

This article will talk something about deploying RoR application to local and remote nginx server.

Deploy RoR on local machine

Like deploying other website, the static file is served via nginx, and the Ruby logic will be handled via some middle-wares, here is the list:

Thin

  1. Install the thin via homebrew

    gem install thin
    
  2. Start the thin server. Since this is a testing deploy, I just execute thin in the project directory.

    thin start
    

After the command executed, you can find some information printed via thin command. The default port of the server is 3000, which should be used to fill the nginx configuration file.

  1. Update the configuration file for nginx. The upstream section should be put in http block.

    upstream todo_app {
    server http://127.0.0.1:3000
    

    }

The location section should be put in server block.

     location / {
     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    off;

     try_files $uri $uri/index.html $uri.html @ruby;     
 }

 location @ruby {
     proxy_pass http://todo_app
 }

The proxy_pass will pass all ruby request to the upstream server. Unix socket can also be used in the upstream section.

  1. Restart the nginx server, the RoR project can be shown in the web browser now.

Passenger

  1. Install passenger via gem

    gem install passenger
    
  2. Install passenger module for nginx

    passenger-install-nginx-module
    

Or you can install nginx and passenger module with brew like this

     brew install nginx --with-passenger

If nginx still report the error that can not find the PassengerLoggingAgent, try to use passenger package-runtime and then get the agent from package passenger-standalone/XXX/support.tar.gz

In the http section, you should specify the value of passenger_root and passenger_ruby. Here is the configuration in my laptop:

     passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.12;
 passenger_ruby /usr/local/bin/ruby;

NOTICE: Make sure to set rails_env variable is set to the same stage with development, seems the default value is production. Here is my configuration section in nginx:

     passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.12;
 passenger_ruby /usr/local/bin/ruby;

 server {
     listen       8080;
     server_name  localhost;
     root /Users/ziming/tmp/learn_rb/rails/todo_app/public;
     passenger_enabled on;
     rails_env development;
 }

Unicorn

  1. Install unicorn via gem

    gem install unicorn
    
  2. Get the sample configuration file from unicorn website

    curl -o config/unicorn.rb https://raw.github.com/defunkt/unicorn/master/examples/unicorn.conf.rb
    

And update the working_directory, pid, stderr_path and stdout_path in the sample configuration file. NOTICE: Need absolute path here.

  1. The left step is the same with Thin, a upstream section should be added to nginx.conf, and redirection should be added to location section.

Deploy remotely via Capistrano

Capistrano is a useful tool for deploying RoR application to remote server(s). The Capistrany package provides several tasks for simplfying the deploying jobs.

  1. Prepare the RoR application

Before deploying, we should prepare the application. Since this only show how to deploy, so we just use the generated project. I have create a repository on bitbucket, and the scm used for this application is mercurial.

First I create the repository DailyCheckIn on butbucket, then I clone the project to local directory dailycheckin. The directory is an empty directory except some mercurial information. After directory ready, I create RoR application via rails new command. Before doing the initialization commit, I should create a .hgignore file based on the .gitignore (Just add syntax: glob at the first line, remove the leader slash in the path, and rename .gitignore to .hgignore). After all things done, commit the new added file and push to the server, then we have a RoR application.

  1. Capify the RoR project

The project should be ‘capified’ before deplying via Captistrano, which can be done via command capify . easily. This command will create Capfile and config/deploy.rb file in current directory. The Capfile is the wrapper, and the tasks is written in file deploy.rb

  1. Configure the Capistrano

Here are the information should be checked before deploying:

* Application name
* Server information 
  * Application layer
  * Wer server
  * Database
* SCM information 
  * Repository location
  * SCM type
* Directory the project should be deployed to

Here is a sample configuration file for the project

    set :application, "DailyCheckIn"
set :repository,  
set :scm, :mercurial
server , :web, :app, :db, :primary => true
set :deploy_to, 
set :use_sudo, false

The detailed information of configuration can be found in [Capistrano document](https://github.com/capistrano/capistrano/wiki/2.x-From-The- Beginning).

  1. Deploy the application

Next step is deploy the application. The first step is setting up the server, Capistrano provide task cap deploy:setup to do this. This task will do a series of mkdir calls. Make sure the permission of directory.

After setting up completed, it is recommended to check the dependencies via cap deploy:check command. Re-run this command after any change to the environment to make sure all check passed.

The next step should be done manually, you should login to the server and make sure the database can meet the requirement configured in the config/database.yml file.

After environment ready, task deploy:update can be used to clone the code to server. The clone operation will create a new snapshot in the releases directory, and link it with symbol link current in top level of depoly directory. Then cap deploy:start can be used to start the services.