Install and configure NGINX and Mongrel for Rails
Some times ago i wrote an article about installing a Rails stack on Debian Etch (our production server), then how to configure Apache 2 + fcgid to run our Rails app.
After several tests with this deployment configuration , we encountered some problems of performance (i will detail what our application does in a future article) :
- First with Apache server, after an idle time, then accessing a page of our application, we should wait for a long time before our page loads. Seems fcgid processes take a long time to (re)start.
- In our application, we deliver some files with a download controller : for bigger files, the download was very long.
We decided recently to switch the Apache2 / fcgid configuration to Mongrel (Ruby HTTP server) + nginx (as proxy in front of Mongrel).
I will explain you how to proceed.
We suppose here you have already installed Ruby , Rails, mySQL.
Connect as root and follow these steps :
First stop Apache2 :
#/etc/init.d/apache2 stop
Install Mongrel
# gem install mongrel
# gem install mongrel_cluster
Install nginx:
# aptitude install nginx
Configure what we have installed
We have to setup our server apps to boot when the server starts, and shutdown gracefully when the server reboots.
Concerning nginx, it already did automatically this setup at install:
# ls -l /etc/rc?.d/*nginx
lrwxrwxrwx 1 root root 15 2008-05-05 11:00 /etc/rc0.d/K20nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root 15 2008-05-05 11:00 /etc/rc1.d/K20nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root 15 2008-05-05 11:00 /etc/rc2.d/S20nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root 15 2008-05-05 11:00 /etc/rc3.d/S20nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root 15 2008-05-05 11:00 /etc/rc4.d/S20nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root 15 2008-05-05 11:00 /etc/rc5.d/S20nginx -> ../init.d/nginx
lrwxrwxrwx 1 root root 15 2008-05-05 11:00 /etc/rc6.d/K20nginx -> ../init.d/nginx
As you can see, for runlevels 0, 1 and 6 there is a K at the beginning of the link, for runlevels 2, 3, 4 and 5, there is a S. Those two letters stands for Kill and Start.
On Debian (and Ubuntu), runlevels 2, 3, 4 and 5 are multi-users runlevels.
Runlevel 0 is Halt.
Runlevel 1 is single user mode
Runlevel 6 is reboot
Remove Apache 2 service
By hand you should remove every link /etc/rc.X/*apache2.
Using update-rc.d is as simple as :
# update-rc.d -f apache2 remove
Removing any system startup links for /etc/init.d/apache2 …
/etc/rc0.d/K09apache2
/etc/rc1.d/K09apache2
/etc/rc2.d/S91apache2
/etc/rc3.d/S91apache2
/etc/rc4.d/S91apache2
/etc/rc5.d/S91apache2
/etc/rc6.d/K09apache2
Add Mongrel service for automatic startup/stop
# cp /usr/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.5/resources/mongrel_cluster /etc/init.d/mongrel_cluster
Edit /etc/init.d/mongrel_cluster and add the following environment setup:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local:/usr/local/sbin:/usr/local/bin
# chmod +x /etc/init.d/mongrel_cluster
# update-rc.d mongrel_cluster defaults
Adding system startup for /etc/init.d/mongrel_cluster …
/etc/rc0.d/K20mongrel_cluster -> ../init.d/mongrel_cluster
/etc/rc1.d/K20mongrel_cluster -> ../init.d/mongrel_cluster
/etc/rc6.d/K20mongrel_cluster -> ../init.d/mongrel_cluster
/etc/rc2.d/S20mongrel_cluster -> ../init.d/mongrel_cluster
/etc/rc3.d/S20mongrel_cluster -> ../init.d/mongrel_cluster
/etc/rc4.d/S20mongrel_cluster -> ../init.d/mongrel_cluster
/etc/rc5.d/S20mongrel_cluster -> ../init.d/mongrel_cluster
But as you can see, the default value is 20 which is pretty different than 91 … a S20 link is started before a S91 and and K91 is kill before K20.
I decided to startup nginx after mongrel, and stop nginx before mongrel. I’ll use 23 for nginx.
First remove nginx symlinks:
# update-rc.d -f nginx remove
Then create symlinks for nginx with custom priorities :
# update-rc.d nginx defaults 23 23
Adding system startup for /etc/init.d/nginx …
/etc/rc0.d/K23nginx -> ../init.d/nginx
/etc/rc1.d/K23nginx -> ../init.d/nginx
/etc/rc6.d/K23nginx -> ../init.d/nginx
/etc/rc2.d/S23nginx -> ../init.d/nginx
/etc/rc3.d/S23nginx -> ../init.d/nginx
/etc/rc4.d/S23nginx -> ../init.d/nginx
/etc/rc5.d/S23nginx -> ../init.d/nginx
Create the folder /etc/mongrel_cluster that our Rails app Mongrel config will live in.
# mkdir /etc/mongrel_cluster
Generate the Rails app Mongrel config file:
# mongrel_rails cluster::configure -e production -p 8001 -N 3 -c /path/to/rails/app -C /path/to/rails/app/config/mongrel_cluster.yml -P /path/to/rails/app/log/mongrel.pid -l /path/to/rails/app/log/mongrel.log –user <user> –group <group> -a 127.0.0.1
Verify the config file (/path/to/rails/app/config/mongrel_cluster.yml)
user: <user>
cwd: /path/to/rails/app
log_file: /path/to/rails/app/log/mongrel.log
port: “8001″
environment: production
group: <group>
address: 127.0.0.1
pid_file: /path/to/rails/app/mongrel.pid
servers: 3
Create a symlink to this file into /etc/mongrel_cluster :
ln -s /path/to/your/rails/app/mongrel_cluster.yml /etc/mongrel_cluster/YOURAPPNAME.yml
Configure nginx
We now need to edit our nginx.conf file found in /etc/nginx/nginx.conf to set it up. Edit the values found in my nginx.conf file and modify it to suit your needs.
Nginx is a powerful UNIX tool.
You have noticed we used here nginx as Reverse-Proxy in front of a Mongrel cluster; if the web-server (Mongrel in our case) cannot handle more load , you can even put nginx before the web-server to use it as web-server to handle requests to static files.
Thanks to nginx flexibility, you can pass any types of requests to web-server server by using location sections (all files, only dynamic content requests or some specific locations in your web-server tree):
proxy_pass http://mongrel:8000/;
proxy_set_header X-Real-IP $remote_addr;
}
It should be fine now! Reboot your server and test everything is up after startup :
# shutdown -r now
Nota : Another tool to test: Varnish, an high-performance HTTP-accelerator.
Tags: debian, Linux, mongrel, mongrel_cluster, nginx, rails, ror
July 2, 2008 at 4:40 pm
Good tutorial! Maybe you should install a code highligthing extension and improve the indentation to make the code more readable on the screen.
One question, why not using the user and group ‘www-data’ for the mongrel_cluster ?
Thanks