PDA

View Full Version : Deploy rails app using SSH/PuTTY/Pageant, SVN, MySQL, Capistrano, Mongrel, nginx - 3


Larry
03-22-2008, 06:18 PM
Mongrel
You've probably been using mongrel as your local web and application server. We'll do the same thing at first: get the web app working with just mongrel before we attempt to stick nginx in front of it.

On the server:

cd /var/www/apps/sample/shared
mkdir config
mongrel_rails cluster::configure -p 8000 -e production -a 127.0.0.1 -N 2 --user yourusername --group root -c /var/www/apps/sample/current

Creates the file: config/mongrel_cluster.yml. Make sure it looks like this (order doesn't matter, only entries do).
Notice we are specifying 2 mongrels in our cluster. It's a good idea to use more than one because Rails is single-threaded.

---
user: yourusername
group: root
cwd: /var/www/apps/sample/current
port: "8000"
servers: 2
environment: production
address: 127.0.0.1
log_file: log/mongrel.log
pid_file: tmp/pids/mongrel.pid


This script allows Mongrel to handle requests from a web server, e.g. nginx. Right now we want to use Mongrel for everything, so comment out the following line:

#address: 127.0.0.1


There are a couple of mongrel init scripts: /etc/init.d/mongrel and /etc/init.d/mongrel_cluster. We'll deal with the latter as we'll be using the cluster. (mongrel_cluster should be installed as a Ruby gem; don't worry, RimuHosting already took care of that.) The file contents are fine as-is, but we need to create a symlink:

cd /etc/mongrel_cluster (this directory is specified in the above-mentioned mongrel_cluster script)
ln -s /var/www/apps/sample/shared/config/mongrel_cluster.yml sample.yml (symlink sample.yml to mongrel_cluster.yml)

Some points about the above operation:

1) The /etc/init.d/mongrel_cluster is hard-coded to load mongrel_cluster configs found in /etc/mongrel_cluster. The sample.yml symlink to /var/www/apps/sample/shared/config/mongrel_cluster.yml ensures that that configuration will get loaded.

2) An "ls -l" command shows that "sample.yml" is indeed a symlink to another file.

3) Notice the linkage between this file and the following line in the Capistrano "deploy.rb" file mentioned above:
set :mongrel_config, "/etc/mongrel_cluster/#{application}.yml"
When expanded: "/etc/mongrel_cluster/sample.yml" - the symlink file we just created.


Are We There Yet?
Almost. Everything should be in place for your first deployment. This is where you hold your breath and get that second beer ready...

At the root of your local project:
cap deploy:cold

Note: You only do a "cap deploy:cold" the very first time you deploy your app. After that, i.e. when you make changes to the code, the command is simply:

cap deploy

Remember how you have to stop and start Mongrel for your code changes to take effect? Well, "cap deploy" tries to stop mongrel and then restart it. Since we haven't started Mongrel at this point we enter "cap deploy:cold", which won't try stopping the server.

If all went well you should be able to point your browser to "http://yourwebsite.com:8000" and see some sort of default page, e.g. "The page you were looking for doesn't exist."
If you put a sample app up there, just ammend your URL to access the app, e.g. "http://yourwebsite.com:8000/people"


Finally: nginx
nginx is a load-balancing, reverse-proxy web server. It will dish out the static content itself (i.e. in "/public/*") and hand off requests for dynamic content to your cluster of mongrels.

The first thing you need to do is uncomment the line we previously commented out in var/www/apps/sample/shared/config/mongrel_cluster.yml:
address: 127.0.0.1

An important thing to know is your document root: /var/www/apps/sample/current/public

There are two files you need to deal with are:
1) init file - /etc/init.d/nginx
2)config file - /usr/local/nginx/conf/nginx.conf


1) Here is an /etc/init.d/nginx that should work as is; no substitutions are necessary:

#!/bin/sh
# v1.0
# nginx - Start, stop, or reconfigure nginx
#
# chkconfig: - 60 50
# description: nginx [engine x] is light http web/proxy server
# that answers incoming ftp service requests.
# processname: nginx
# config: /usr/local/nginx/conf/nginx.conf
# pidfile: /usr/local/nginx/logs/nginx.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

BINARY=/usr/local/nginx/sbin/nginx
CONF_FILE=/usr/local/nginx/conf/nginx.conf
PID_FILE=/usr/local/nginx/logs/nginx.pid
[ -x $BINARY ] || exit 0

RETVAL=0
prog="nginx"

start() {
# Start daemons.
if [ -e $BINARY ] ; then

echo -n $"Starting $prog: "
$BINARY -c $CONF_FILE
RETVAL=$?
[ $RETVAL -eq 0 ] && {
touch /var/lock/subsys/$prog
success $"$prog"
}
echo
else
RETVAL=1
fi
return $RETVAL
}

stop() {
# Stop daemons.
echo -n $"Shutting down $prog: "
kill -s QUIT `cat $PID_FILE 2>/dev/null`
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
return $RETVAL
}

# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
reconfigure)
if [ -f /var/lock/subsys/$prog ]; then
kill -s HUP `cat $PID_FILE 2>/dev/null`
RETVAL=$?
fi
;;
status)
status $prog
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|reconfigure|status}"
exit 1
esac

exit $RETVAL

However, you do need to make it executable:
chmod +x /etc/init.d/nginx

2) Here is a /usr/local/nginx/conf/nginx.conf that should work; substitutions are needed for "yourusername", "yourwebsite.com", and wherever you see "sample". ("sample" will work if you created a sample app called "sample". Just remember to change it to the name of your real web application when you come through here the second time around.)

# NOTE: (Some) Field explanations can be found at: http://wiki.codemongers.com/NginxRubyonRailsMongrel

user yourusername;
worker_processes 2;
pid logs/nginx.pid;
error_log logs/default_error.log notice;

events {
worker_connections 1024;
}

http {
include conf/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/nginx_access.log main;
error_log logs/nginx_error.log info;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 30;

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

upstream mongrels {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
}

server {
listen 80;
server_name yourwebsite.com;
# The all-important 'document root'
root /var/www/apps/sample/current/public;

access_log logs/sample_access.log main;
error_log logs/sample_error.log notice;

# This is for capistrano's disable web task. It rewrites all the requests
# to the 'maintenance.html' page if it exists in the document root.
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html last;
break;
}

location / {
index index.html index.htm;

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 false;
proxy_max_temp_file_size 0;

# Directly serve static content
location ~ ^/(images|javascripts|stylesheets)/ {
expires 10y;
}

# If the file exists as a static file serve it directly
# without running all the other rewite tests on it.
if (-f $request_filename) {
break;
}

# Directly serve cached pages.
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}

# Let mongrels handle the request
if (!-f $request_filename) {
proxy_pass http://mongrels;
break;
}
}

error_page 500 502 503 504 /500.html;
}
}

After you create this file you can give it a sanity test thusly:
cd /usr/local/nginx/conf
/usr/local/nginx/sbin/nginx -t -c nginx.conf

RimuHosting sets up your environment using Apache as the web server. The following commands add nginx and then switch from Apache to nginx:

chkconfig --add nginx
chkconfig nginx on
chkconfig httpd off

service httpd stop
service nginx start

nginx should now be running. Point your browser to http://yourwebsite.com and then, as we did before, http://yourwebsite.com/people

By the way, the commands to stop and then start nginx are:
service nginx stop
service nginx start