Seventh Octave

We're Starters. We write about culture, design and the business of software.

We believe software should be beautiful and inspired. Follow us as we build @TechOctave.

How to host a Rails app with Phusion Passenger for Nginx TVD Sep 03

6 comments Latest by TVD

I believe Phusion Passenger for Nginx will do for Rails Deployment what jQuery did for JavaScript Development. So it should come as no surprise that this will be an opinionated Rails deployment tutorial. Simply put, I couldn't phantom deploying Rails without Passenger for Nginx.

Today I'm going to run you through getting your Rails app running on Ubuntu, Ruby Enterprise Edition (REE), Rails, Nginx and Phusion Passenger for Nginx. Lastly, I'll quickly show you how to successfully deploy your Rails app to a sub URI without any 403 Forbidden errors.

Here are my notes from one of my client's latest Rails deployment.

Ruby Enterprise Edition (REE):

We're going to start by installing Ruby Enterprise Edition (REE). Download the latest .deb REE package, then install it:

wget http://rubyforge.org/frs/download.php/71100/ruby-enterprise_1.8.7-2010.02_i386_ubuntu10.04.deb

sudo dpkg -i ruby-enterprise_1.8.7-2010.02_i386_ubuntu10.04.deb

ruby -v

You should see something similar to ruby 1.8.7 (2010-04-19 patchlevel 253) ... Ruby Enterprise Edition 2010.02. Now, update your RubyGem package manager and all of your installed gems:

sudo gem update --system
sudo gem update

Ruby on Rails

At this point you should make sure you've installed the Ruby on Rails gem. Don't worry, you've probably already done that. Here's the command to install Rails (just in case):

sudo gem install rails
rails -v

Install, Configure and Manage Nginx

Install Nginx

First, let's install the Open SSL library. You're going to need this later for SSL support and management:

sudo aptitude install libssl-dev

Next, we are going to install the Passenger for Nginx module. This module will install both Nginx and Passenger:

sudo passenger-install-nginx-module

Follow the default options. Soon, you'll be prompted with two options to either select 1 or to select 2.

Choose option 2 if you need to install additional Nginx modules. One module that comes to mind is the Nginx SSL module.

For this tutorial, select option 1. Let the install finish. Congrats, you've just installed a blazing fast Webserver (Nginx) and Rails application server (Passenger)!

You will also need to create a user and group for nginx. Issue the following command to do so:

adduser --system --no-create-home --disabled-login --disabled-password --group nginx

Finally, let's create an init.d script and have it boot at startup. The init.d will allow us to control Nginx:

sudo nano /etc/init.d/nginx

Copy and paste the following Nginx init script into the new 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=/opt/nginx/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/opt/nginx/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 /opt/nginx/logs/$NAME.pid \
        --exec $DAEMON -- $DAEMON_OPTS || true
    echo "$NAME."
    ;;
  stop)
    echo -n "Stopping $DESC: "
    start-stop-daemon --stop --quiet --pidfile /opt/nginx/logs/$NAME.pid \
        --exec $DAEMON || true
    echo "$NAME."
    ;;
  restart|force-reload)
    echo -n "Restarting $DESC: "
    start-stop-daemon --stop --quiet --pidfile \
        /opt/nginx/logs/$NAME.pid --exec $DAEMON || true
    sleep 1
    start-stop-daemon --start --quiet --pidfile \
        /opt/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 /opt/nginx/logs/$NAME.pid \
          --exec $DAEMON || true
      echo "$NAME."
      ;;
  status)
      status_of_proc -p /opt/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

To save the file using nano, press ctrl+o, then enter. Then exit by pressing ctrl+x.

Change permission on the script to make it an executable:

sudo chmod +x /etc/init.d/nginx

Have the new executable run at startup:

sudo /usr/sbin/update-rc.d -f nginx defaults

Now, you have the power to start, stop and restart Nginx. Start your shiny new Nginx Webserver with this command:

sudo /etc/init.d/nginx start

Navigate to your server's IP address using Firefox or your favorite browser. You should see "Welcome to Nginx!" This means Nginx is up-and-running. Now we can focus on configuring Nginx for your Rails web application.

Configure Nginx

Edit your Nginx configuration:

sudo nano /opt/nginx/conf/nginx.conf

Make sure Nginx knows the location of your passenger and ruby installation:

. . .
http {
    passenger_root /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.15;
    passenger_ruby /usr/local/bin/ruby;
. . .
    server {
    . . .
    }
}

For fun, let's modify our Server section to deploy our Rails app to a Sub URI:

server {
    listen 80;
    server_name domain.com;
    charset utf-8;
    root /www/domain.com/public_html;
    passenger_enabled on;
    passenger_base_uri /blog;
    rails_spawn_method smart;
    rails_env production;
}

To do this, we have to make a symlink from our Rails app's public directory to the document root of our static website:

ln -s /www/domain.com/railsapp/public /www/domain.com/public_html/blog

This command will create a symlink called blog in the document root /www/domain.com/public_html/.

Remember, if you want to make the sub uri work, do not create a folder called blog in the document root. This will get you a nice Rails sub uri 403 Forbidden error from your passenger Nginx setup.

For a typical Xen VPS setup, you should also think about adding the following tweaks to your Nginx conf:

user                      nginx nginx;
worker_processes          4;
worker_connections        1024;
passenger_max_pool_size   6;

Read more about the the passengermaxpool_size directive. The maximum value depends on your server's cpu processor and other factors. Do experiment!

When you're finished, save the file and restart Nginx:

sudo /etc/init.d/nginx restart

Manage Nginx

In the future you can restart the entire Nginx server or only restart your application with the following command:

touch /www/domain.com/blog/tmp/restart.txt

The next time you load your Rails app it will restart.

Passenger also has some pretty cool built-in monitoring applications. You can access them using these commands:

sudo passenger-status
sudo passenger-memory-stats

I suggest installing another utility to see what's using memory on your entire server. It's called htop:

sudo apt-get install htop
sudo htop

Well, you're done really! I hope this helps.

For the uninitiated, deploying to Ubuntu (or any Linux distro) can be daunting. But, once you get over having nothing but a black screen to work with, you'll realize how unshackled and productive you feel. Good luck Beloved!

If you enjoyed this post, subscribe for updates (it's free).

Email Address:

6 comments so far

kaysov 18 Dec 10

I cannot get my blogcast installation to work when I use nginx. It cannot find stylesheets? /stylesheets/error.css" failed (2: No such file or directory) Help me!

Rajinder Yadav 18 Dec 10

Hello Tian, I don't know why, but nginx insists on loading it's own index.html page my nginx.conf file looks like this server { listen 3000; server_name localhost; root /home/yadav/dev/rails/projects/TestApp/public; passenger_enabled on; rails_spawn_method smart; rails_env development; I just want to use nginx for my development testing. What am I doing wrong? Kind Regards, Rajinder Yadav

TVD 18 Dec 10

@kaysov Looks like a classic Permission issue. Hopefully, you've solved this by now. Just-in-case, let's try a couple things: You will need to create a user and group for nginx. Issue the following command to do so: adduser --system --no-create-home --disabled-login --disabled-password --group nginx Declare the user in /opt/nginx/conf/nginx.conf . . . user nginx nginx; worker_processes 4; . . . Restart nginx sudo /etc/init.d/nginx restart Give nginx permission to access your files chmod -R 774 /www/domain.com/public_html chmod -R 774 /www/domain.com/blog chown -R nginx:nginx /www/domain.com/public_html chown -R nginx:nginx /www/domain.com/blog

TVD 18 Dec 10

@RajinderYadav By default, Nginx listens on port 80 for web traffic. Nginx is probably loading its default index.html because it cannot access port 3000. For Nginx to access port 3000, you'll have to open that port on your server. Check out some suggestions below. If that doesn't work, the Phusion Passenger User Guide (Nginx Version) might be a good next step. Check your /etc/hosts file to make sure localhost is registered sudo nano /etc/hosts Add this line to your hosts file 127.0.0.1 localhost Clean up any Permission issues See above... Make sure your nginx.conf is good. Here's a basic nginx.conf: user nginx nginx; worker_processes 1; events { worker_connections 1024; } http { passenger_root /usr/local/lib/ruby/gems/1.8/gems/passenger-2.2.15; passenger_ruby /usr/local/bin/ruby; include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name domain.com; charset utf-8; root /www/domain.com/public_html; passenger_enabled on; passenger_base_uri /blog; rails_spawn_method smart; rails_env development; } } Restart nginx sudo /etc/init.d/nginx restart Hope things work out for you. Nginx is a beautiful Web Server and Passenger is the Bugatti of Rails Application Servers.

kaysov 21 Dec 10

I still get a 403 error in spite of doing everything like you discussed in your Rails sub URI post! What am I missing?

TVD 21 Dec 10

@kaysov Head over to Stack Overflow. That will give you a chance to really layout your *.configs, deploy scripts, etc. Best to stop knocking your head against the wall at this point. Sometimes it just takes a fresh pair of eyes for that Eureka moment. If you like, you can post your SO Question link here too. That way the Community can learn from your time in the desert. Also, I can jump in if I see you aren't being helped. Good luck brother!

Comments are closed