Inveigled By Design

The art of persuasive design

Setting up Nginx with Ruby on Rails using Passenger and Ruby Enterprise Edition

Nginx

In the first article of this series I reviewed the steps I took to secure the server and get a basic, reasonably secure set up. The next step is to get Nginx setup for ruby. I chose Nginx because of it’s low memory usage, which is important when trying to squeeze the most out of a smaller VPS.

Setting up Ruby Enterprise Edition:

Phusion Passenger

I’m going to use Ruby Enterprise Edition exclusively for my ruby apps. Again, this is to optimize memory usage on the system.


First install a few prerequisites:

sudo aptitude install libssl-dev libreadline5-dev

Get a directory ready for loading source into:

mkdir ~/sources
cd ~/sources
mkdir ree
cd ree

Get the ruby code and run the installer (be sure to get the latest version). I just accepted the defaults when running the installer. If you change any directories, you’ll need to make the same changes below. Also if you use a different version of ruby enterprise edition, you may need to update the paths below.:

wget http://rubyforge.org/frs/download.php/58677/ruby-enterprise-1.8.6-20090610.tar.gz
tar zxf ruby-enterprise-1.8.6-20090610.tar.gz
sudo ./ruby-enterprise-1.8.6-20090610/installer


Now use links to make this the primary ruby installation:

sudo ln -s /opt/ruby-enterprise-1.8.6-20090610/bin/ruby /usr/local/bin/
sudo ln -s /opt/ruby-enterprise-1.8.6-20090610/bin/gem /usr/local/bin/
sudo ln -s /opt/ruby-enterprise-1.8.6-20090610/bin/rake /usr/local/bin/
sudo ln -s /opt/ruby-enterprise-1.8.6-20090610/bin/rails /usr/local/bin/

Verify the installation and links with:

which ruby    // should be /usr/local/bin/ruby
which gem     // should be /usr/local/bin/gem
which rake    // should be /usr/local/bin/rake
which rails   // should be /usr/local/bin/rails

Now update and install passenger:

sudo gem install rubygems-update
sudo gem install passenger

Setting up Nginx with Passenger Support:

We have to compile Nginx from source to integrate passenger support.

First install a few prerequisites:

sudo aptitude install libc6 libpcre3 libpcre3-dev libpcrecpp0 libssl0.9.8 libssl-dev zlib1g zlib1g-dev

Now get the Nginx source (be sure to get the latest version):

cd ~/sources
mkdir nginx
cd nginx
wget http://sysoev.ru/nginx/nginx-0.7.61.tar.gz
tar zxf nginx-0.7.61.tar.gz
cd nginx-0.7.61

Configure the build to use passenger (be sure to use the path for the version of ruby you installed in the add-module section):

sudo ./configure --sbin-path=/usr/local/sbin --with-http_ssl_module --add-module=/opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/passenger-2.2.4/ext/nginx

Now build, install and start nginx:

sudo make
sudo make install
sudo /usr/local/sbin/nginx

You’ll see a warning about passenger being disabled. We’ll fix that in a minute. Now you can navigate to the nginx welcome page using http://”your ip address”. The page should say “Welcome to nginx”.

When installed from source, the nginx initialization script doesn’t get created, so lets stop nginx and create that now:

sudo kill `cat /usr/local/nginx/logs/nginx.pid`
sudo nano /etc/init.d/nginx

Copy and paste this into the nginx script file:

#! /bin/sh

### BEGIN INIT INFO
# Provides:          nginx
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nginx web server
# Description:       starts nginx using start-stop-daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/sbin/nginx
NAME=nginx
DESC=nginx

test -x $DAEMON || exit 0

# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
    . /etc/default/nginx
fi

set -e

. /lib/lsb/init-functions

case "$1" in
  start)
    echo -n "Starting $DESC: "
    start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \
        --exec $DAEMON -- $DAEMON_OPTS || true
    echo "$NAME."
    ;;
  stop)
    echo -n "Stopping $DESC: "
    start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \
        --exec $DAEMON || true
    echo "$NAME."
    ;;
  restart|force-reload)
    echo -n "Restarting $DESC: "
    start-stop-daemon --stop --quiet --pidfile \
        /usr/local/nginx/logs/$NAME.pid --exec $DAEMON || true
    sleep 1
    start-stop-daemon --start --quiet --pidfile \
        /usr/local/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
    echo "$NAME."
    ;;
  reload)
      echo -n "Reloading $DESC configuration: "
      start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \
          --exec $DAEMON || true
      echo "$NAME."
      ;;
  status)
      status_of_proc -p /usr/local/nginx/logs/$NAME.pid "$DAEMON" nginx && exit 0 || exit $?
      ;;
  *)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2
    exit 1
    ;;
esac

exit 0

Make sure the script is executable and ensure that it starts when the system boots:

sudo chmod +x /etc/init.d/nginx
sudo /usr/sbin/update-rc.d -f nginx defaults

Now you can start, restart, stop nginx using the commands:

sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx restart
sudo /etc/init.d/nginx stop

I like to set up my web sites in directories similar to the approach the apache server takes. This involves setting up a few directories and breaking up the default nginx config file into smaller ones.

First create the directories. Sites-available is where our site configurations will go and sites enabled will only contain our active sites:

sudo mkdir /usr/local/nginx/sites-available
sudo mkdir /usr/local/nginx/sites-enabled

Now backup the default config file and create a new one for the default web site. You may want to refer back to the config file to set up a default ssl site:

sudo cp /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.back
sudo nano /usr/local/nginx/conf/nginx.conf

Now copy and paste this into the nginx.conf file. If you used a different version or install location for ruby enterprise edition, be sure to update the passenger statements below with the correct path.:

user www-data www-data;
worker_processes  4;

events {
    worker_connections  1024;
}

http {
    passenger_root /opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/passenger-2.2.4;
    passenger_ruby /opt/ruby-enterprise-1.8.6-20090610/bin/ruby;

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

    sendfile        on;
    tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  5;
    tcp_nodelay        off;

    gzip  on;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_types      text/plain text/css application/x-javascript text/xml
                    application/xml application/xml+rss text/javascript;

    include /usr/local/nginx/sites-enabled/*;

}

Now we’ve included the initialization for passenger, so our warning about passenger being disabled should go away. We’re also telling nginx to include our sites-enabled directory, so any sites we link to that directory will be served up.

We’re in the home stretch, we just need a default site set up:

sudo nano /usr/local/nginx/sites-available/default

Copy and paste this into the file:

server {
    listen       80;
    server_name  localhost;

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

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }

}

Now we just need to enable the site and restart nginx:

sudo ln -s /usr/local/nginx/sites-available/default /usr/local/nginx/sites-enabled/default
sudo /etc/init.d/nginx restart

That will be the procedure for any sites you want nginx to serve. Create a configuration file in the sites-available folder and then create a symlink to the sites-enabled folder to enable it. If you want to remove a site, just remove the link in the sites-enabled folder. Always restart nginx to see the changes.

You can verify the installation by going back to http://”your ip address”. You should see the “Welcome to nginx” page.

For sites that use ruby, you’ll need to include “passenger_enabled on;” in their configuration as shown here:

server {
    listen       80;
    server_name  www.yourSiteName.com;

    location / {
        root   /pathToTheSiteFiles;
        index  index.html;
        passenger_enabled on;
    }
}

Okay, now the web server is set up and we’re ready to serve up our ruby apps with passenger. Next we’ll get php going and then start installing some apps.

6 Responses to “Setting up Nginx with Ruby on Rails using Passenger and Ruby Enterprise Edition”

  1. [...] Setting up Nginx with Ruby on Rails using Passenger and Ruby Enterprise Edition [...]

  2. [...] the previous article, we set up Nginx with Ruby Enterprise Edition and Passenger support. Now we need to get php running [...]

  3. (unless I’m missing something….)
    You’re going to need

    passenger_enabled on;

    somewhere. I assume it’d be best to set this in the server {} block so you have granular control of which sites need passenger and which don’t. If all sites are using passenger it can be included in the main nginx.conf

    Great article though Thanks!

  4. You are correct, Alex. I didn’t really set up a specific site in the article, so I didn’t mention that. I’ve fixed it now. Thanks for the feedback.

  5. Excellent article – had me up and running in minutes. Super big thank you.

    Linked back to your blog from here:

    http://rubyredbricks.com/2010/4/9/redmine-on-linode-part-1

    Had a tiny issue with " and & HTML escape in the nginx script file – minor, but had to do a quick find/replace before saving.

    Thanks again – hugely appreciated.

  6. Ah.. hilarious.. your blog swallowed the HTML escapes in my post.. :)

Leave a Reply

Creative Commons License
Content on this site is licensed under a Creative Commons Attribution-Share Alike 3.0 License
Copyright © 2009 Inveigled Software