Ruby on Rails, Capistrano, Mongrel and nginx on Gentoo
A few months ago I wrote quite popular :) manual how to install and use RoR, Capistrano and Mongrel with Apache on Gentoo. Things changed a little as the time goes and after some experiences with the nginx server on a Slicehost slice, I decided to write an updated manual and to use the nginx server instead of the Apache HTTP Server. Let’s start :)
A deployment process should be straightforward and automatic as much as possible. The main reason is that this process will be repeated many times and omitted or wrong steps usually cause hey-what-are-you-doing-the-site-does-not-work calls or e-mails from your customers. Fortunately, there is a nice tool for Ruby on Rails applications — Capistrano.
Now we know about a tool to automate the deployment of an application, but we need to deploy our application to a production environment — I decided for the combination of Mongrel and nginx.
…and everything runs on Gentoo :)
Here is my short howto:
Introduction
Let’s define CLIENT as a computer where you are developing an application, SERVER as a computer where you are going to deploy it and APP as the name of your application.
I assume that Gentoo is installed on both computers.
I decided to create a special user APP for the application on the server (if you do not like it, then all paths /home/APP replace with your favourite path ;).
I prefer the PostgreSQL database.
A short remark for copying text — if you would like to copy a text without any line numbers (they are fine for reading, but not for using on a command line or in a text file) click on the [Show Plain Code] link for each block of code or configuration file to display an unformatted text.
I. Client Software Installation
We will need to install Capistrano and Mongrel. (I assume that you already installed Ruby on Rails on your computer. :)
We need to unmask mongrel related packages – the mongrel_cluster
is masked (29. August 2007) in the portage. Add the following lines to the /etc/portage/package.keywords
file:
-
www-servers/mongrel_cluster
-
www-servers/mongrel
-
dev-ruby/fastthread
And install necessary software:
-
emerge capistrano mongrel mongrel_cluster
II. Server Software Installation
We will need to install Ruby, Ruby on Rails, Capistrano, Mongrel and nginx.
Add necessary use flags to the /etc/portage/package.use
file, e.g.:
-
dev-ruby/rails postgres
to install a PostgreSQL support in RoR.
We need to unmask mongrel related packages, similarly as for the client side, add the following lines to the /etc/portage/package.keywords
file:
-
www-servers/mongrel_cluster
-
www-servers/mongrel
-
dev-ruby/fastthread
and install all necessary software:
(and maybe other dev-ruby/* packages that you used for your application). Sudo is needed for starting Mongrel.
III. Server Side Configuration
Let’s create a special user for the application (not necessary):
-
useradd -d /home/APP -m APP
-
passwd APP
Open the /etc/sudoers
file and add the following line:
-
APP ALL=(ALL) ALL
The main reason for creating a special user was a fact that the sudo command has to be available for a user. Frankly, I do not like the sudo command (sorry, Ubuntu guys). With
su -
it is clear when I have root privileges and when not (on Ubuntu I usually typesudo bash
:).
I also created a new database user APP:
-
su –
-
su – postgres
-
createuser APP
and a new production database:
-
createdb -E utf-8 APP_production
IV. Client Side Configuration
Go to the application directory and create a configuration for Mongrel:
it will create the config/mongrel_cluster.yml
file; basically you do not need to edit it.
Then create a configuration for Capistrano (do not forget that APP is the name of your application):
-
cap –apply-to . APP
and in this case we need to modify the generated file config/deploy.rb
— I added or changed the following lines:
-
span style=”color:#008000; font-style:italic;”>#you set the APP name with the cap command
-
"APP"
-
#a path to your repository
-
"svn+ssh://USERNAME@SVN_SERVER/projects/#{application}/trunk"
-
-
role :web, "SERVER""SERVER"
-
role :db, "SERVER"#where to deploy (copy the files) on the server; I created a special user APP for the application (if you do not like it, replace the /home/#{application} part with your path
-
"/home/#{application}/production/#{application}"
-
set :mongrel_conf, "#{current_path}/config/mongrel_cluster.yml"
-
#if the server login name is different to the development computer login name; in my case the user name is the APP name
-
set :user, "APP"
It is also necessary to update the config/database.yml
file:
-
#no changes needed, just to show the development configuration
-
#I changed the username to the database user name on the server
-
Do not forget to add all new files and commit all changes (because Capistrano uses files in your repository).
V. Deployment
Create the basic structure on the server (files from the repository is not used in this step):
If there is something wrong: check the config/deploy.rb
file; try to log to the server manually e.g. ssh APP@SERVER
or ssh APP@SERVER -v -v -v
; did you add and commit the config/deploy.rb
file?
Let Capistrano do the magic :)
-
rake remote:cold_deploy
If there is something wrong: check the config/deploy.rb
file; try to check out the repository manually on the server.
To check if everything went fine, access the http://SERVER:8000
link or the http://localhost:8000
link on the server. If you have a firewall, probably only the second option will work — you can use the console browser lynx
or to be more professional ;) wget http://localhost:8000
.
Anytime you can delete the
/home/APP/production
directory on the server and start from scratch. All files are safely stored in your repository. (Except the data in the database on the server.)
If you use migrations to create databases and to insert initial data (of course that you are! :), call the following command to run migrations on the server:
-
rake remote:migrate
For any next deployments use the following command:
-
rake remote:deploy
VI. nginx Configuration
Firstly define the following values:
- SERVER_IP is the IP address of your server, e.g. 1.2.3.4 ;)
- SERVER_NAME is the name of your server as it is specified in a DNS record for your SERVER_IP, e.g. company.com.
- APP.SERVER_NAME is a suggested value that would point to your application, e.g. application.company.com.
The (below) described configuration does the following:
- all http or https requests
http://SERVER_NAME
go to the standard web directory, by default to the/var/www/localhost/htdocs
directory. - http requests
http://APP.SERVER_NAME
go to your RoR application APP.
Log to the server as root (do you remember? su -
:) and create or update (make a backup) the nginx configuration stored in the /etc/nginx/nginx.conf
file:
-
user nginx nginx;
-
worker_processes 1;
-
-
error_log /var/log/nginx/error_log info;
-
-
events {
-
worker_connections 8192;
-
use epoll;
-
}
-
-
http {
-
include /etc/nginx/mime.types;
-
default_type application/octet-stream;
-
-
log_format main
-
‘$remote_addr – $remote_user [$time_local] ‘
-
‘"$request" $status $bytes_sent ‘
-
‘"$http_referer" "$http_user_agent" ‘
-
‘"$gzip_ratio"’;
-
-
client_header_timeout 10m;
-
client_body_timeout 10m;
-
send_timeout 10m;
-
-
connection_pool_size 256;
-
client_header_buffer_size 1k;
-
large_client_header_buffers 4 2k;
-
request_pool_size 4k;
-
-
gzip on;
-
gzip_min_length 1100;
-
gzip_buffers 4 8k;
-
gzip_types text/plain;
-
-
output_buffers 1 32k;
-
postpone_output 1460;
-
-
sendfile on;
-
tcp_nopush on;
-
tcp_nodelay on;
-
-
keepalive_timeout 75 20;
-
-
ignore_invalid_headers on;
-
-
index index.html;
-
-
upstream mongrel {
-
server 127.0.0.1:8000;
-
server 127.0.0.1:8001;
-
}
-
-
server {
-
listen SERVER_IP; # e.g. 1.2.3.4
-
server_name SERVER_NAME; # e.g. www.company.com
-
-
access_log /var/log/nginx/localhost.access_log main;
-
error_log /var/log/nginx/localhost.error_log info;
-
-
root /var/www/localhost/htdocs;
-
}
-
-
server {
-
listen SERVER_IP; # e.g. 1.2.3.4
-
server_name APP.SERVER_NAME; # e.g. application.company.com
-
-
access_log /var/log/nginx/localhost.access_log main;
-
error_log /var/log/nginx/localhost.error_log info;
-
-
root /home/APP/production/APP/impl/public;
-
-
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 false;
-
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://mongrel;
-
break;
-
}
-
}
-
}
-
-
##ssl
-
server {
-
listen SERVER_IP:443; # e.g. 1.2.3.4:443
-
server_name SERVER_NAME; # e.g. www.company.com
-
-
ssl on;
-
ssl_certificate /etc/ssl/nginx/nginx.pem;
-
ssl_certificate_key /etc/ssl/nginx/nginx.key;
-
-
access_log /var/log/nginx/localhost.ssl_access_log main;
-
error_log /var/log/nginx/localhost.ssl_error_log info;
-
-
root /var/www/localhost/htdocs;
-
}
-
}
or simply download the nginx.cong file to your server.
Do not forget to replace SERVER_IP, SERVER_NAME and APP with your values :)
Restart the nginx server:
and test the http://APP.SERVER_NAME
link — your application should appear :)
The http://SERVER_NAME
link should display content stored in the standard web directory, by default the /var/www/localhost/htdocs
directory. This could be an ideal place for your static pages and files.
Of course, do not forget to add the nginx service to the default runlevel to start it when the server starts:
To start the Mongrel instance I added the following line to the /etc/conf.d/local.start
file:
and to stop it nicely, I added the following line to the /etc/conf.d/local.stop
file:
You can stop server with the
cluster::stop
action and start with thecluster::start
action.
Hopefully I helped you to configure your production environment.
Any comments are welcome…