Rails, Capistrano, Mongrel and Apache (with SSL) on Gentoo

There is a happy occasion in the development of an application — deployment. Users will use it, you will receive (hopefully) some money, there will be some bugs.. well, maybe not so happy occasion.. ;>
In most situations you will have to repeat a deployment process several times (bug fixes, new features, etc.). Maybe the process is not very complicated, but an automation will minimise possible mistakes such as typos or omitted commands.
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 Apache.
…and everything runs on Gentoo :)
Let’s start — 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:
-
emerge ruby-termios capistrano
bacause there is not ebuild for Mongrel, you have to install it with gem:
-
gem install -y mongrel
-
gem install -y mongrel_cluster
(The -y option is a shortcut to the --include-dependencies option.)
II. Server Software Installation
Let’s install necessary software:
-
gem install –include-dependencies mongrel
-
gem install –include-dependencies mongrel_cluster
We will need Apache 2.2 (because the mod_proxy_balancer) that is masked in the portage (7. January 2007), so it is necessary to unmask it:
add the following lines to the /etc/portage/package.unmask file:
-
net-www/apache
-
dev-libs/apr
-
dev-libs/apr-util
to the /etc/portage/package.keywords file (thanks to Steve for his comment how to improve this):
-
~net-www/apache-2.2.3
-
~dev-libs/apr-1.2.7
-
~dev-libs/apr-util-1.2.7
and install it:
-
emerge apache
If you plan to support SSL (for a secure communication between a client and the server), do not forget to add the ssl use flag for Apache — add the following line to the /etc/portage/package.use file:
-
net-www/apache ssl
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 sh:).
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:
-
mongrel_rails cluster::configure -e production -p 8000 -a 127.0.0.1 -N 2 -c /home/APP/production/APP/current
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:
-
require ‘mongrel_cluster/recipes’
-
-
#you set the APP name with the cap command
-
set :application, "APP"
-
#a path to your repository
-
set :repository, "svn+ssh://USERNAME@SVN_SERVER/projects/#{application}/trunk"
-
-
role :web, "SERVER"
-
role :app, "SERVER"
-
role :db, "SERVER", :primary => true
-
-
#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
-
set :deploy_to, "/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
-
development:
-
adapter: postgresql
-
database: APP_development
-
username: ondrej
-
host: 127.0.0.1
-
encoding: unicode
-
-
#I changed the username to the database user name on the server
-
production:
-
adapter: postgresql
-
database: APP_production
-
username: APP
-
host: localhost
-
encoding: unicode
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):
-
rake remote:setup
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/productiondirectory 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. Apache Configuration
Log to the server as root (do you remember? su - :) and add the -D PROXY option to the /etc/conf.d/apache2 file. Because I have Apache only for one application, my configuration looks like:
-
APACHE2_OPTS="-D INFO -D LANGUAGE -D SSL -D SUEXEC -D PROXY"
i.e. I removed the -D DEFAULT_VHOST and -D SSL_DEFAULT_VHOST options.
For the new application we will create a new virtual host — create a new /etc/apache2/vhosts.d/01_APP_vhost.conf file with the following content[RoRBook] (do not forget that APP is the application name):
-
<Proxy balancer://mongrel_cluster>
-
BalancerMember http://127.0.0.1:8000
-
BalancerMember http://127.0.0.1:8001
-
</Proxy>
-
-
<VirtualHost *:80>
-
ServerName SERVER
-
DocumentRoot /home/APP/production/APP/current/public
-
<Directory "/home/APP/production/APP/current/public" >
-
Options FollowSymLinks
-
AllowOverride None
-
Order allow,deny
-
Allow from all
-
</Directory>
-
-
RewriteEngine On
-
-
# Check for maintenance file and redirect all requests
-
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
-
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
-
RewriteRule ^.*$ /system/maintenance.html [L]
-
-
# Rewrite index to check for static
-
RewriteRule ^/$ /index.html [QSA]
-
-
# Rewrite to check for Rails cached page
-
RewriteRule ^([^.]+)$ $1.html [QSA]
-
-
# Redirect all non-static requests to cluster
-
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
-
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
-
</VirtualHost>
Restart the Apache web server:
-
/etc/init.d/apache2 restart
and test the http://SERVER link (or http://localhost on the server) — your application should appear :)
Of course, do not forget to add the Apache service to start when the server starts:
-
rc-update add apache2 default
To start the Mongrel instance I added the following line to the /etc/conf.d/local.start file:
-
mongrel_rails cluster::restart -C /home/APP/production/APP/current/config/mongrel_cluster.yml
You can stop server with the
cluster::stopaction and start with thecluster::startaction.
VII. Apache SSL Configuration
As a bonus, here are instructions how to setup the SSL support. I wanted to have only one application that has to be accessible only via HTTPS, i.e. if a user uses insecure HTTP, (s)he will be automatically redirected to secure HTTPS.
Change the /etc/apache2/vhosts.d/01_APP_vhost.conf file:
-
<Proxy balancer://mongrel_cluster>
-
BalancerMember http://127.0.0.1:8000
-
BalancerMember http://127.0.0.1:8001
-
</Proxy>
-
-
<VirtualHost *:443>
-
ServerName SERVER:443
-
DocumentRoot /home/APP/production/APP/current/public
-
<Directory "/home/APP/production/APP/current/public" >
-
Options FollowSymLinks
-
AllowOverride None
-
Order allow,deny
-
Allow from all
-
</Directory>
-
-
RequestHeader set X_FORWARDED_PROTO ‘https’
-
-
RewriteEngine On
-
-
# Check for maintenance file and redirect all requests
-
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
-
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
-
RewriteRule ^.*$ /system/maintenance.html [L]
-
-
# Rewrite index to check for static
-
RewriteRule ^/$ /index.html [QSA]
-
-
# Rewrite to check for Rails cached page
-
RewriteRule ^([^.]+)$ $1.html [QSA]
-
-
# Redirect all non-static requests to cluster
-
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
-
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
-
-
CustomLog /var/log/apache2/APP_log combined
-
-
SSLEngine on
-
-
SSLCertificateFile /etc/apache2/ssl/APP.crt
-
SSLCertificateKeyFile /etc/apache2/ssl/APP.key.unsecure
-
</VirtualHost>
-
-
<VirtualHost *:80>
-
ServerName SERVER
-
-
# Redirects only the URL http://SERVER to https://SERVER, but not http://SERVER/anything
-
#Redirect permanent / https://SERVER
-
-
# More general redirect, it redirect all URLs http://SERVER/anything to https://SERVER/anything
-
RewriteEngine on
-
RewriteRule ^/(.*) https://SERVER/$1 [redirect=permanent]
-
</VirtualHost>
It is necessary to create a certificate file and a certificate key files[ApacheDoc]:
-
#key file, do not forget the pass-phrase
-
openssl genrsa -des3 -out APP.key 1024
-
#certificate file; for the "Common Name" (CN) type the SERVER name or the SERVER IP address
-
openssl req -new -x509 -nodes -sha1 -days 365 -key APP.key -out APP.crt
-
#decrypted key file; not very secure
-
openssl rsa -in APP.key -out APP.key.unsecure
and copy the last two created files to the /etc/apache2/ssl/ directory.
I use the decrypted key file, because the Apache web server asks for the pass-phrase when it starts with an encrypted key file.
Hopefully I helped you to configure your production environment. Btw. this is my first production installation :), so if you have better experiences, please, you are welcome to write a comment…
[RoRBook] Agile Web Development with Rails, 2nd edition
[ApacheDoc] http://httpd.apache.org/docs/2.0/ssl/ssl_faq.html










