Jan 07 2011

RVM + Rails 3 + nginx + Phusion Passenger

Category: Rails,RubyRussell Pitre @ 2:44 pm

Recently, I have been dabbling in the Ruby/Rails world for the first time, and as a newcomer there’s lots of new information from many different sources that I thought I would put together for other newbies. ¬†After much research and head scratching this is the Rails stack that I’ve come up with, minus the database, that will be next. I hopeful this setup will be a rock solid solution, and from what I’ve Googled around it at least appears to consist of proven frameworks and technologies.

Here are the technologies I have chosen:

  • Ubuntu 10.10 (Maverick)
  • RVM 1.1.8
  • nginx 0.8.54
  • Phusion Passenger 3.0.2
  • Ruby 1.9.2 p136
  • Rails 3.0.3

So let me explain a bit about why I chose each item in the list above. I chose Ubuntu as the OS because I want more Unix/Linux experience, seems to be one of the more popular Linux distros out there and its the Linux OS that I have the most familiarity with. Next is Ruby/Rails, I chose the latest versions of each because even though I don’t have a specific application in mind to build yet, I might as well spend my time learning the latest and greatest today so if and when I do build my next app in Rails, those versions will be the norm. Moving on, I kind of stumbled onto RVM during my research and glad I did. I love it’s ease of use, ability to setup multiple environments without worrying about version conflicts, and it’s integration with Capistrano (future blog post). Nginx is light-weight, both in features and memory utilization, fast, I like the configuration syntax and seems to be gaining popularity. Lastly, Phusion Passenger was chosen because it’s recommended here on rubyonrails.org.

So lets get started and put the pieces together.

Setup a new user account.

Create a new user account, change the password and then add the new user account to sudoers file. The rails application will run as this user.

$ sudo useradd -s /bin/bash -m app-user   		# add user
$ sudo passwd app-user					# change password
$ sudo /usr/sbin/visudo					# edit sudoers file

# Add line below just below 'root ALL=(ALL) ALL':
app-user ALL=(ALL) ALL

From here on out we’ll be executing the installation as this user.

$ su app-user

Install RVM

Install the dependencies needed for RVM and then install.

$ sudo apt-get install git curl build-essential vim libcurl4-openssl-dev
$ bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )

Brilliant! Can’t get any easier than this.

 
Update ~/.bashrc file (remember this is the app-user’s .bashrc file).

$ vim ~/.bashrc

# This snippet should placed at the end of the .bashrc file.
[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"  # This loads RVM into a shell session.

Exit as app-user and then su app-user again to load rvm into the shell session.

Install Ruby prequisites

Double-check what the Ruby dependencies are using:

$ rvm notes

Install the dependencies

$ sudo apt-get install build-essential bison openssl libreadline6 libreadline6-dev \
		curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev \
		sqlite3 libxml2-dev libxslt-dev autoconf

Install Ruby

Install Ruby using rvm.

$ rvm package install zlib
$ rvm package install openssl
$ rvm install 1.9.2 --with-zlib-dir=$rvm_path/usr --with-openssl-dir=$rvm_path/usr

Create GemSet

$ rvm --create use 1.9.2@myapplication
$ rvm --default use 1.9.2@myapplication
$ ruby -v  # test it

Install Phusion Passenger

$ gem install passenger

Install nginx using the passenger installer

Download and then extract nginx source, remember this location. The passenger installer can download it for you as part of option 1 during the install, but I chose option 2 so that I can supply extra arguments to the nginx installer.

$ wget http://nginx.org/download/nginx-0.8.54.tar.gz
$ tar xvf nginx-0.8.54.tar.gz
$ rvmsudo passenger-install-nginx-module  # rvmsudo is required in order to install nginx to /opt/nginx

Create an Upstart job to start nginx at boot time. Create a new file /etc/init/nginx.conf and then add the following:

$ sudo vim /etc/init/nginx.conf

The complete contents of the nginx.conf file are:

	description "Nginx HTTP Server"

	start on filesystem
	stop on runlevel [!2345]

	respawn

	exec /opt/nginx/sbin/nginx -g "daemon off;"

Next, we’ll want to restart to verify our upstart script works.

$ sudo shutdown -r now

Verify nginx is up and running

$ sudo initctl list | grep nginx

You should see:

nginx start/running, process 678

…Or use a browser and visit http://localhost

Install Rails 3

su back in with app-user if you’re not already.

$ gem install rails --version 3.0.3

Create a sample rails application to verify our setup

$ sudo mkdir /rails_apps
$ sudo chown app-user:app-user /rails_apps
$ cd /rails_apps

$ rails new myapplication
$ cd /rails_apps/myapplication
$ bundle install
$ rails generate scaffold Post name:string title:string content:text
$ RAILS_ENV=production rake db:migrate

Configure your rails app to work with nginx/passenger

Open nginx.conf to configure nginx

$ sudo vim /opt/nginx/conf/nginx.conf

Change the second line for the user to ‘app-user’

You will then need to add a server block looking similar to this:

	server {
	listen 80;
	server_name localhost;
	root /rails_apps/myapplication/public;   # <--- be sure to point to 'public'!
	passenger_enabled on;
	}

Restart nginx once again

$ sudo service nginx restart

Use a browser to test app

You will most likely see an error in /www/my-application/log/production.log that says something like “attempt to write a readonly database”. You will need to figure out your permissions with the /my-application/db/production.sqlite3 directory and file. However, if you’re rails app is configured to use a different rdms other than SQLite like MySQL of PostgreSQL, this will probably won’t be an issue.

References:

12 Responses to “RVM + Rails 3 + nginx + Phusion Passenger”

  1. Tweets that mention RVM + Rails 3 + nginx + Phusion Passenger | Big Rock Software -- Topsy.com says:

    [...] This post was mentioned on Twitter by kayne lee. kayne lee said: RVM + Rails 3 + nginx + Phusion Passenger http://bit.ly/gUoCJm [...]

  2. rad_g says:

    Nice, beautiful, thank you for this.

  3. helloqidi says:

    Thank you very much!

  4. Saravanan says:

    Thanks.. you have put a lot effort for this and its nice of you to share this.. It saved me a lot of time !!

  5. Luan says:

    Any idea why I still get the blank screen “Welcome to nginx!” after restart with rails app?

    Please help.

    Thanks,
    Luan

    • Russell Pitre says:

      I have no idea why, can you post the contents of your nginx.conf?

      • luan says:

        Hi Russell,

        I commented out

        location / {
        root html;
        index index.html index.htm;
        }

        from my nginx.conf and it worked. Either I need to change this link into my app or remove it all together. Did you have this in your nginx.conf. It came with the default installed.

        Thanks a lot for your help.
        Luan

  6. luan says:

    Hi Russell,

    Sorry for a long nginx.conf. I didn’t create a separate user as your post, but I use my user which is luan. Here is my nginx.conf

    When I go to browser, http://127.0.0.1 or http://localhost: I only get
    “Welcome to nginx”. Thanks for your help.

    ####################################################
    #user nobody;
    user luan;
    #user www-data;

    worker_processes 1;

    #error_log logs/error.log;
    #error_log logs/error.log notice;
    #error_log logs/error.log info;

    #pid logs/nginx.pid;

    events {
    worker_connections 1024;
    }

    http {
    passenger_root /usr/local/rvm/gems/ruby-1.9.2-p180/gems/passenger-3.0.5;
    #passenger_ruby /usr/local/rvm/wrappers/ruby-1.9.2-p180/ruby;
    passenger_ruby /usr/local/bin/passenger_ruby;

    include mime.types;
    default_type application/octet-stream;

    #log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
    # ‘$status $body_bytes_sent “$http_referer” ‘
    # ‘”$http_user_agent” “$http_x_forwarded_for”‘;

    #access_log logs/access.log main;

    sendfile on;
    #tcp_nopush on;

    #keepalive_timeout 0;
    keepalive_timeout 65;

    #gzip on;

    server {
    listen 80;
    server_name localhost;
    root /opt/rails/myapplication/public; # <— be sure to point to 'public'!5
    passenger_enabled on;
    #rails_env development;
    #rack_env development;

    #charset koi8-r;

    #access_log logs/host.access.log main;

    location / {
    root html;
    index index.html index.htm;
    }

  7. Ved says:

    I performed the same steps on a VPS – http://46.102.244.155/ But I keep on seeing the default steps. Any idea what needs to be done ? My conf file looks like – https://gist.github.com/1058440
    (I am using user root here)

  8. Jaman says:

    Very nice walkthrough. It really helped me a lot. Thanks!

  9. Indy says:

    Thanks for this. Very useful and precise. Saved me a lot of time.

    I used Ubuntu 10.10 on Amazon. And it worked like a charm.

    I changed a couple of things:

    a) when compiling nginx, I specified the option: –with-http_ssl_module

    b) I attached a volume to the instance and mounted it at /mnt/data-store/

    And stored the rails_apps folder there: /mnt/data-store/rails_apps/

    Also, changed nginx conf to point to that folder.

Leave a Reply