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.
Nginx: http://wiki.nginx.org/
Unicorn: http://unicorn.bogomips.org/
Ramaze: http://ramaze.net/
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 (www.domain3.com) to run my Rack app (Ramaze). But first I create a normal virtual host (www.domain3.com), 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/domain3.com
$ mkdir ~/public_html/domain3.com/{public,private,log,backup}
$ gedit ~/public_html/domain3.com/public/index.html # create home index.html file
It's content looks like this:<html>
<head>
<title>domain3.com</title>
</head>
<body>
<h1>domain3.com</h1>
</body>
</html>
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/domain3.comHere is it's content.
server {
listen 80;
server_name www.domain3.com;
rewrite ^/(.*) http://domain3.com/$1 permanent;
}
server {
listen 80;
server_name domain3.com;
access_log /home/socrateos/public_html/domain3.com/log/access.log;
error_log /home/socrateos/public_html/domain3.com/log/error.log;
location / {
root /home/socrateos/public_html/domain3.com/public/;
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/domain3.com /etc/nginx/sites-enabled/domain3.comFinally 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.
127.0.1.1 domain1.com 127.0.1.1 www.domain1.com 127.0.1.1 domain2.com 127.0.1.1 www.domain2.com 127.0.1.1 domain3.com # new domain added to be used for Ramaze app 127.0.1.1 www.domain3.com # new domain added to be used for Ramaze appI added similar entries to C:\Windows\System32\drivers\etc\hosts on my Windows Visita.
192.168.12.13 domain1.com 192.168.12.13 www.domain1.com 192.168.12.13 domain2.com 192.168.12.13 www.domain2.com 192.168.12.13 domain3.com # new domain added to be used for Ramaze app 192.168.12.13 www.domain3.com # new domain added to be used for Ramaze appRestart my Nginx server.
$ sudo /etc/init.d/nginx stop Stopping nginx: nginx. $ sudo /etc/init.d/nginx start Starting nginx: nginx.Now test http://www.domain3.com 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=0.0.0.0:8080 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 readyHere 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 http://www.domain3.com, 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 (domain3.com) 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/domain3.com # open the domain3.com (conf) file for editing.Here is the modified contents. This is based on slicehost's "Ubuntu Intrepid - Nginx, rails and thin".
upstream backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name www.domain3.com;
rewrite ^/(.*) http://domain3.com/$1 permanent;
}
server {
listen 80;
server_name domain3.com;
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;
break;
}
}
}
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 http://www.domain3.com. 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.confThe following is its contents. It is based on http://unicorn.bogomips.org/examples/unicorn.conf.rb 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:
# http://unicorn.bogomips.org/examples/unicorn.conf.rb
# http://blog.xambr.com/2010/01/16/running-ramaze-with-unicorn-nginx-and-god/
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/unicorn-master.pid"
# 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
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
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
### BEGIN INIT INFO
# 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
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/var/lib/gems/1.9.1/bin/unicorn
DAEMON_OPTS="-c /home/socrateos/public_html/apps/app1/unicorn.conf -E production -D"
NAME=unicorn
DESC="Unicorn app for app1"
PID=/home/socrateos/public_html/apps/app1/tmp/pids/unicorn-master.pid
case "$1" in
start)
echo -n "Starting $DESC: "
$DAEMON $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
kill -QUIT `cat $PID`
echo "$NAME."
;;
restart)
echo -n "Restarting $DESC: "
kill -QUIT `cat $PID`
sleep 1
$DAEMON $DAEMON_OPTS
echo "$NAME."
;;
reload)
echo -n "Reloading $DESC configuration: "
kill -HUP `cat $PID`
echo "$NAME."
;;
*)
echo "Usage: $NAME {start|stop|restart|reload}" >&2
exit 1
;;
esac
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 unicornYes!
Finally, go to http:\\www.domain3.com to see if I can see my Ramaze app.
The answer is YES.



This comment has been removed by a blog administrator.
ReplyDeleteThanks for your tutorial, it help me a lot today :)
ReplyDelete