valibuk.net

A place for opinions and notes of a valibuk.

Ruby on Rails, Capistrano, Mongrel and nginx on Gentoo

Tagged with: — ondrej at 1:25 am on Thursday, August 30, 2007

Ruby on Rails 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.

Larry the CowNow 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:

  1. www-servers/mongrel_cluster
  2. www-servers/mongrel
  3. dev-ruby/fastthread

And install necessary software:

  1. 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.:

  1. 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:

  1. www-servers/mongrel_cluster
  2. www-servers/mongrel
  3. dev-ruby/fastthread

and install all necessary software:

  1.  

(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):

  1. useradd -d /home/APP -m APP
  2. passwd APP

Open the /etc/sudoers file and add the following line:

  1. 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 type sudo bash :).

I also created a new database user APP:

  1. su –
  2. su – postgres
  3. createuser APP

and a new production database:

  1. createdb -E utf-8 APP_production

IV. Client Side Configuration

Go to the application directory and create a configuration for Mongrel:

  1.  

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

  1. 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:

  1. span style=”color:#008000; font-style:italic;”>#you set the APP name with the cap command
  2. "APP"
  3. #a path to your repository
  4. "svn+ssh://USERNAME@SVN_SERVER/projects/#{application}/trunk"
  5.  
  6. role :web, "SERVER""SERVER"
  7. 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
  8. "/home/#{application}/production/#{application}"
  9. set :mongrel_conf, "#{current_path}/config/mongrel_cluster.yml"
  10. #if the server login name is different to the development computer login name; in my case the user name is the APP name
  11. set :user, "APP"

It is also necessary to update the config/database.yml file:

  1. #no changes needed, just to show the development configuration
  2. #I changed the username to the database user name on the server
  3.  

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

  1.  

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

  1. 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:

  1. rake remote:migrate

For any next deployments use the following command:

  1. 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:

  1. user nginx nginx;
  2. worker_processes 1;
  3.  
  4. error_log /var/log/nginx/error_log info;
  5.  
  6. events {
  7.         worker_connections  8192;
  8.         use epoll;
  9. }
  10.  
  11. http {
  12.         include  /etc/nginx/mime.types;
  13.         default_type    application/octet-stream;
  14.  
  15.         log_format main
  16.                 ‘$remote_addr – $remote_user [$time_local] ‘
  17.                 ‘"$request" $status $bytes_sent ‘
  18.                 ‘"$http_referer" "$http_user_agent" ‘
  19.                 ‘"$gzip_ratio"’;
  20.                                                                               
  21.         client_header_timeout   10m;
  22.         client_body_timeout     10m;
  23.         send_timeout        10m;
  24.  
  25.         connection_pool_size        256;
  26.         client_header_buffer_size       1k;
  27.         large_client_header_buffers     4 2k;
  28.         request_pool_size              4k;
  29.  
  30.         gzip on;
  31.         gzip_min_length 1100;
  32.         gzip_buffers    4 8k;
  33.         gzip_types      text/plain;
  34.  
  35.         output_buffers  1 32k;
  36.         postpone_output 1460;
  37.  
  38.         sendfile        on;
  39.         tcp_nopush      on;
  40.         tcp_nodelay     on;
  41.  
  42.         keepalive_timeout       75 20;
  43.  
  44.         ignore_invalid_headers  on;
  45.  
  46.         index index.html;
  47.  
  48.         upstream mongrel {
  49.                 server 127.0.0.1:8000;
  50.                 server 127.0.0.1:8001;
  51.         }
  52.  
  53.         server {
  54.                 listen    SERVER_IP;      # e.g. 1.2.3.4
  55.                 server_name     SERVER_NAME;    # e.g. www.company.com
  56.  
  57.                 access_log      /var/log/nginx/localhost.access_log main;
  58.                 error_log       /var/log/nginx/localhost.error_log info;
  59.  
  60.                 root /var/www/localhost/htdocs;
  61.         }
  62.  
  63.         server {
  64.                 listen    SERVER_IP;              # e.g. 1.2.3.4
  65.                 server_name     APP.SERVER_NAME;        # e.g. application.company.com
  66.  
  67.                 access_log      /var/log/nginx/localhost.access_log main;
  68.                 error_log       /var/log/nginx/localhost.error_log info;
  69.  
  70.                 root /home/APP/production/APP/impl/public;
  71.  
  72.                 location / {
  73.                         proxy_set_header  X-Real-IP  $remote_addr;
  74.                         proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  75.                         proxy_set_header Host $http_host;
  76.                         proxy_redirect false;
  77.                         if (-f $request_filename/index.html) {
  78.                                 rewrite (.*) $1/index.html break;
  79.                         }
  80.                         if (-f $request_filename.html) {
  81.                                 rewrite (.*) $1.html break;
  82.                         }
  83.                         if (!-f $request_filename) {
  84.                                 proxy_pass http://mongrel;
  85.                                 break;
  86.                         }
  87.                 }
  88.         }
  89.  
  90.         ##ssl
  91.         server {
  92.                 listen    SERVER_IP:443;  # e.g. 1.2.3.4:443
  93.                 server_name     SERVER_NAME;    # e.g. www.company.com
  94.                
  95.                 ssl on;
  96.                 ssl_certificate  /etc/ssl/nginx/nginx.pem;
  97.                 ssl_certificate_key     /etc/ssl/nginx/nginx.key;
  98.                
  99.                 access_log      /var/log/nginx/localhost.ssl_access_log main;
  100.                 error_log       /var/log/nginx/localhost.ssl_error_log info;
  101.        
  102.                 root /var/www/localhost/htdocs;
  103.         }
  104. }

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:

  1.  

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:

  1.  

To start the Mongrel instance I added the following line to the /etc/conf.d/local.start file:

  1.  

and to stop it nicely, I added the following line to the /etc/conf.d/local.stop file:

  1.  

You can stop server with the cluster::stop action and start with the cluster::start action.


Hopefully I helped you to configure your production environment.

Any comments are welcome…

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • DZone
  • Digg
  • Reddit
  • Technorati
  • Furl
  • NewsVine
  • Slashdot
  • Ma.gnolia
  • StumbleUpon

4 Comments »

Comment by Vince

October 29, 2007 @ 6:03 am

thank you so much for this writeup. It’s been very helpful!

Comment by ondrej

November 13, 2007 @ 1:55 pm

that is nice to hear. you are welcome :)

Comment by Fred

November 14, 2007 @ 8:31 pm

Nice man, works smooth
I use it on my Gentoo at EC2 amazon.

I only changed line 55
55. server_name SERVER_NAME;

to be like
server_name myapp.com http://www.myapp.com;

thanks for the post

we are all gentoo lovers.

Comment by ondrej

November 15, 2007 @ 12:29 am

hi Fred,

i added comments to the configuration file. i hope it will help.

thank you for your comment :)

have a nice day

RSS feed for comments on this post. TrackBack URI

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Comment Preview


commercial break :)

Make an account on slicehost.com -- a really good hosting where you have your own virtual machine. I installed Gentoo there = I like it very much ;)