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
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