Sunday, August 14, 2011

Running a Rack app (Ramaze) with Nginx/Unicorn on Ubuntu (11.04)

I want to setup a Rack app on a virtual host on my Ubuntu 11.04 for my tiny intranet. I am already running multiple virtual hosts ( and on my Ubuntu. This time, I want to add another virtual host ( that invokes a Rack application.

1. Requirements.

Ubuntu - a Linux distribution
Ruby - a scripting language
Nginx - a web server that handles multiple virtual hosts
Unicorn - web server to be used to runs behind Nginx
Ramaze - a Rack web framework ("Mini Rails")

2. Resources.

Silpsen: Setting up Unicorn with Nginx
slicehost: Ubuntu Intrepid - Nginx, rails and mongrels
slicehost: Ubuntu Intrepid - Nginx, rails and thin
Tom Kersten: Setting up Ubuntu with Nginx, Unicorn, ree, rv
Maxime Rousseaux-Bridle blog: Running Ramaze with Unicorn, Nginx and God

3. Create a virtual host.
My ultimate goal is to create a virtual host ( to run my Rack app (Ramaze). But first I create a normal virtual host (, without running any web app. Later I will create a web app, which will take over the control of incoming requests.

The first step to create a virtual host is to crate a directory structure and place an index.html file in its public folder.
$ mkdir ~/public_html/
$ mkdir ~/public_html/{public,private,log,backup}
$ gedit ~/public_html/   # create home index.html file
It's content looks like this:
Then I create a normal virtual host file for Nginx. Later I will modify it to redirect its requests to my Rack (Ramaze) app.
$ sudo gedit /etc/nginx/sites-available/
Here is it's content.
server {
            listen   80;
            rewrite ^/(.*)$1 permanent;

server {
            listen   80;

            access_log /home/socrateos/public_html/;
            error_log /home/socrateos/public_html/;

            location / {
                        root   /home/socrateos/public_html/;
                        index  index.html;
Now enable the host, by creating a symlink file into /etc/nginx/sites-enabled directory.
$ sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/
Finally update the /etc/hosts file by adding a new domain name. (My tiny intranet does not need/use DNS.) I just manually edit hosts file in each PC.          # new domain added to be used for Ramaze app      # new domain added to be used for Ramaze app
I added similar entries to C:\Windows\System32\drivers\etc\hosts on my Windows Visita.      # new domain added to be used for Ramaze app  # new domain added to be used for Ramaze app
Restart my Nginx server.
$ sudo /etc/init.d/nginx stop
Stopping nginx: nginx.
$ sudo /etc/init.d/nginx start
Starting nginx: nginx.
Now test with my browser.
The result looks like this as expected. So my new virtual host is working.

4. Create a Rack App (Ramaze)

I now build a Rack (Ramaze) app. Then do a quick test run with Unicorn server, without going through Nginx.
$ cd ~/public_html/      
$ mkdir apps/          # a parent directory for all my web apps
$ cd apps/
$ ramaze create app1   # create a Ramaze app
The application has been generated and saved in app1
$ cd app1/
$ mkdir tmp            
$ mkdir tmp/pids       # for unicorn master pid
$ mkdir log            # for nginx and unicorn logs
$ unicorn              # a quick test run with unicorn server
I, [2011-08-08T00:08:11.149051 #3759]  INFO -- : listening on addr= fd=3
I, [2011-08-08T00:08:11.149263 #3759]  INFO -- : worker=0 spawning...
I, [2011-08-08T00:08:11.149838 #3759]  INFO -- : master process ready
I, [2011-08-08T00:08:11.150249 #3761]  INFO -- : worker=0 spawned pid=3761
I, [2011-08-08T00:08:11.150372 #3761]  INFO -- : Refreshing Gem list
I, [2011-08-08T00:08:11.480209 #3761]  INFO -- : worker=0 ready
Here is the result from http://localhost:8080, directly accessing Unicorn server. Later, after I setup Unicorn to run behind Nginx, I will access our app from, where my nginx server transfers control to Unicorn server, which actually serves our web app.

5. Make Unicorn run behind Nginx

At this point, I have two web servers running independently: Nginx (for a few virtual domains) at port 80 and Unicorn (for Ramaze app) at port 8080. I am now going to modify the configuration of one of nginx's virtual domains ( so that Ngix will transfer control to Unicorn if web requests are for this the domain. In other words, Unicorn will be working as a server behind the Nginx server.
sudo gedit /etc/nginx/sites-available/    # open the (conf) file for editing.
Here is the modified contents. This is based on slicehost's "Ubuntu Intrepid - Nginx, rails and thin".
upstream backend {

server {
            listen   80;
            rewrite ^/(.*)$1 permanent;

server {
            listen   80;

            access_log /home/socrateos/public_html/apps/app1/log/access.log;
            error_log /home/socrateos/public_html/apps/app1/log/error.log;

            root   /home/socrateos/public_html/apps/app1/public/;
            index  index.html;

            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;

                          if (-f $request_filename/index.html) {
                                           rewrite (.*) $1/index.html break;

                          if (-f $request_filename.html) {
                                           rewrite (.*) $1.html break;

                          if (!-f $request_filename) {
                                           proxy_pass http://backend;


Restart Nginx.
$ sudo /etc/init.d/nginx stop
Stopping nginx: nginx.
$ sudo /etc/init.d/nginx status
 * could not access PID file for nginx
$ sudo /etc/init.d/nginx start
Starting nginx: nginx.
Then go to And Voila! We are now seeing a Rack app running under Unicorn server behind a Nginx web server.

6. Daemonize Unicorn

The last step is to run Unicorn as a daemon and start it when Ubuntu starts up. To do this, first, I create a new conf file for Unicorn. I will name it unicorn.conf and place it in app's root directory.
gedit ~/public_html/apps/app1/unicorn.conf
The following is its contents. It is based on and "Running Ramaze with Unicorn, Nginx and God" by Maxime Rousseaux-Bridle. For a detailed information, see Unicorn::Configurator.

# unicorn.conf
# (ruby code)
# Based on the following examples: 

APP_ROOT = "/home/socrateos/public_html/apps/app1"

worker_processes 4
working_directory APP_ROOT

# listen on both a Unix domain socket and a TCP port
listen "{APP_ROOT}/tmp/unicorn.sock", :backlog => 64
listen 8080, :tcp_nopush => true

# Location of master process PID file
pid "#{APP_ROOT}/tmp/pids/"

# Location of stderr/stdout logs
stderr_path "#{APP_ROOT}/log/unicorn.stderr.log"
stdout_path "#{APP_ROOT}/log/unicorn.stdout.log"

# combine REE with "preload_app true" for memory savings
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true

Next, I create an init script file unicorn and placed it in /etx/init.d/ directory to launch Unicorn as a daemon.
#! /bin/sh

# File: /etc/init.d/unicorn

# Provides:          unicorn
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the unicorn web server
# Description:       starts unicorn

DAEMON_OPTS="-c /home/socrateos/public_html/apps/app1/unicorn.conf -E production -D"
DESC="Unicorn app for app1"

case "$1" in
 echo -n "Starting $DESC: "
 echo "$NAME."
 echo -n "Stopping $DESC: "
        kill -QUIT `cat $PID`
 echo "$NAME."
 echo -n "Restarting $DESC: "
        kill -QUIT `cat $PID`
 sleep 1
 echo "$NAME."
        echo -n "Reloading $DESC configuration: "
        kill -HUP `cat $PID`
        echo "$NAME."
 echo "Usage: $NAME {start|stop|restart|reload}" >&2
 exit 1

exit 0

Then make sure to start it on start up.
$ sudo update-rc.d -f unicorn defaults
 Adding system startup for /etc/init.d/unicorn ...
   /etc/rc0.d/K20unicorn -> ../init.d/unicorn
   /etc/rc1.d/K20unicorn -> ../init.d/unicorn
   /etc/rc6.d/K20unicorn -> ../init.d/unicorn
   /etc/rc2.d/S20unicorn -> ../init.d/unicorn
   /etc/rc3.d/S20unicorn -> ../init.d/unicorn
   /etc/rc4.d/S20unicorn -> ../init.d/unicorn
   /etc/rc5.d/S20unicorn -> ../init.d/unicorn

7. Test

I rebooted the machine to check if Unicorn started automatically.
$ ps aux | grep unicorn
root      1151  0.6  0.2  14604 10900 ?        Sl   23:47   0:00 unicorn master -c /home/socrateos/public_html/apps/app1/unicorn.conf -E production -D                                    
root      1192  0.0  0.2  14604  9088 ?        Sl   23:47   0:00 unicorn worker[0] -c /home/socrateos/public_html/apps/app1/unicorn.conf -E production -D                                 
root      1195  0.0  0.2  14604  9088 ?        Sl   23:47   0:00 unicorn worker[1] -c /home/socrateos/public_html/apps/app1/unicorn.conf -E production -D                                 
root      1198  0.0  0.2  14604  9088 ?        Sl   23:47   0:00 unicorn worker[2] -c /home/socrateos/public_html/apps/app1/unicorn.conf -E production -D                                 
root      1201  0.0  0.2  14604  9092 ?        Sl   23:47   0:00 unicorn worker[3] -c /home/socrateos/public_html/apps/app1/unicorn.conf -E production -D                                 
1001      1820  0.0  0.0   5128   860 pts/0    S+   23:48   0:00 grep --color=auto unicorn
Finally, go to http:\\ to see if I can see my Ramaze app.
The answer is YES.


  1. This comment has been removed by a blog administrator.

  2. Thanks for your tutorial, it help me a lot today :)