Hi all as I worked on setting up 4 to 5 servers, I thought its better to document the stuff so that I/developers can refer it, So I am documenting the step-by-step process for setting up the slicehost server for rails application work with nginx as a web server and mongrel as a rails application server.

Update

To update your system:

yum update

MySQL

to install mysql client and server apps

yum install mysql-server

The client package “mysql” will automatically be installed as a dependency.

Apache

yum install httpd

PHP5

To install php with soap, xml and mysql plugins:

yum install php php-soap php-xml php-mysql

some other php plugin utilities that are common:

yum install php-mbstring php-gd

Ruby

yum install ruby

Utilities

other useful utilities:

yum install nano wget elinks subversion vi

Nginx

install nginx web server:

yum install nginx

Mongrel Cluster

install mongrel_cluster:

gem install mongrel_cluster –include-dependencies

Setup your nginx configuration for your rails application and mongrel_cluster (proxy).

Below you found sample config file for nginx.conf (normally located in “/etc/nginx/conf/nginx.conf”)

user  deploy;
worker_processes  1;
error_log   logs/error.log debug;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
  include        conf/mime.types;
  default_type   application/octet-stream;
  sendfile        on;
  #tcp_nopush     on;
  keepalive_timeout  65;
  tcp_nodelay        on;
  gzip  on;
  gzip_min_length  1100;
  gzip_buffers     4 8k;
  gzip_types       text/plain;
  upstream mongrel {
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
  }
  server {
    listen       80;
    server_name  example.com;
    root /var/www/apps/example/current/public;
    index  index.html index.htm;
    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;
      }
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
  }
}

Restart the nginx server:

/etc/init.d/nginx restart

Mongrel Configuration:

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

You can test cluster with

To Start:

mongrel_rails cluster::start

To Stop:

mongrel_rails cluster::stop

To Restart:

mongrel_rails cluster::restart

Capistrano Configuration:

Then create a configuration for Capistrano:

cap –apply-to .

we need to modify the generated file config/deploy.rb:

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"

Make necessary changes to the config/database.yml file.

Capistrano Deployment:

Create the basic structure on the server:

cap deploy:setup

For the first deployment you can use cold deploy:

cap cold_deploy

After that for next deployments you have to use:

cap deploy

You can also run migration from capistrano with:

cap deploy:migrate*

* Note: It wont work for me, it migrating to the previous release available in the releses folder, So I suggest you manually run migration on server.

That’s it, your server is ready to run.
Hope this documentation will be helpful to you, Enjoy ;-).

Posted by Bhushan Ahire, filed under Ruby On Rails. Date: July 29, 2008, 9:38 am | No Comments »

I am using google apps for my domain www.bhushangahire.com

For one of my rails application I am using this domain mail account setup for sending mails.
But I am not able to send the mail with the default smtp setings we use for sending mail.

So I search on net and I found the Goggle Apps consider its in different way. Which is TLS ans SSH service, which is not by default comes with the Action mailler.

ActionMailer can’t send emails using GMail out of the box. To add this functionality do the following configuration in your rails application:

  1. Create the file lib/smtp_tls.rb
    require "openssl"
    require "net/smtp"
    
    Net::SMTP.class_eval do
    private
    def do_start(helodomain, user, secret, authtype)
    raise IOError, 'SMTP session already started' if @started
    check_auth_args user, secret, authtype if user or secret
    
    sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
    @socket = Net::InternetMessageIO.new(sock)
    @socket.read_timeout = 60 #@read_timeout
    
    check_response(critical { recv_response() })
    do_helo(helodomain)
    
    raise 'openssl library not installed' unless defined?(OpenSSL)
    starttls
    ssl = OpenSSL::SSL::SSLSocket.new(sock)
    ssl.sync_close = true
    ssl.connect
    @socket = Net::InternetMessageIO.new(ssl)
    @socket.read_timeout = 60 #@read_timeout
    do_helo(helodomain)
    
    authenticate user, secret, authtype if user
    @started = true
    ensure
    unless @started
    # authentication failed, cancel connection.
    @socket.close if not @started and @socket and not @socket.closed?
    @socket = nil
    end
    end
    
    def do_helo(helodomain)
    begin
    if @esmtp
    ehlo helodomain
    else
    helo helodomain
    end
    rescue Net::ProtocolError
    if @esmtp
    @esmtp = false
    @error_occured = false
    retry
    end
    raise
    end
    end
    
    def starttls
    getok('STARTTLS')
    end
    
    def quit
    begin
    getok('QUIT')
    rescue EOFError
    rescue OpenSSL::SSL::SSLError
    end
    end
    end
  2. Add the following lines to config/environment.rb and replace the values with the appropriate username and password:
    require 'smtp_tls'
    ActionMailer::Base.perform_deliveries = true
    ActionMailer::Base.raise_delivery_errors = true
    ActionMailer::Base.server_settings = {
    :address => "smtp.gmail.com",
    :port => 587,
    :domain => "mydomain.com",
    :authentication => :plain,
    :user_name => "username@mydomain.com",
    :password => "password"
    }

    *Note:To work your domain with “mydomain.com” you have to configure your MX records to work Gmail mail sending functionality out of box.

    Else you can use a temporary address @mydomain.com.test-google-a.com, I have not tested with this as I have already configure my MX records.

    You can get more information on changing http://www.google.com/support/a/bin/answer.py?answer=33352.

    Hope this information is useful to you. ;-)

Posted by Bhushan Ahire, filed under Ruby On Rails. Date: July 28, 2008, 9:36 am | 2 Comments »

Couple of months back, one of our clients requested an enhancement - To show some parts of the application in pop ups. I told him it would be pretty easy. I gave him the link of Redbox and said we have done this many times, it should be easy. His reply was… “Scroll up and down the pages, the pop up doesn’t seem to be moving with the page” . I said “Yes, it doesn’t”. He said he wants that to happen.

After looking around for next couple of hours, I came across Thickbox. Now how could I miss this at the first place. It was what I exactly wanted for sometime now. And it had support for iframe also. So I went ahead and downloaded the required files namely jquery-latest.js, thickbox.js and thickbox.css. For those who don’t know about jquery – Jquery is a Javascript library to handle browser events, add AJAX features to your application etc. In next 15 minutes I was ready with the sample code to check if things really work and to my disappointment it didn’t work and moreover my existing AJAX features broke. When I opened the jquery library I found that it also uses ‘$’ like prototype.js, hence a conflict.

The solution for this problem is described here.

After making the required changes it worked. I was happy, client was happy until one fine day SSL came into picture. I use nginx as my web server and had done SSL setup before. I could setup the SSL but when I clicked one of the links which use thickbox to open up the popup, it just opened the content of the popup on a new page. After playing with the code from sometime I found that the j-query file gets truncated because its too big and also the page takes lot of time to download.

Jquery provides a compact version of its library. Using this file solved my problem.

Posted by Aditya, filed under Ruby On Rails. Date: July 23, 2008, 9:23 pm | No Comments »

I have my Ruby on Rails application running on EC2.

EC2 is a web service that helps in elastic computation across the web. It is elastic because the computation is very resizable. When compared with Plain Hosting it provides the following advantages:

  • Unlike traditional hosting services EC2 provides resources that can be used unlimitedly,
  • EC2 provides full control on the resource where in the entire resource configurations can be manipulated according to the users requirement and
  • EC2’s service doesn’t require users to pay a fixed, up-front fee irrespective of their actual computing power used but instead the pay is very dynamic and the computed based on the usage of the resource.

The usage of the EC2 image becomes easier if ruby on rails application is to be hosted. As rails provide gems for additional utilities, it provides a gem called as “ec2onrails” that makes the hosting even simpler.

The following are the steps in using the EC2 image:

  • Install the gem – gem install ec2onrails

  • Add the configuration files to the rails application – There are 3 files that is essential in order to use the image:

    • Capfile – The Capistrano file that includes the line, require ‘ec2onrails/recipes’ in addition to the existing config details. This makes the ec2onrails libraries available during deployment.

    • S3.yml – Instance stores appear to an instance as a local disk. They just survive intentional and unintentional reboots of the instance unless the instance terminates or the underlying drive fails. Hence the backup or replication of important data is very essential and it happens in Amazon S3. This happens using the configurations in this S3.yml file. The details comprises of aws_access_key, aws_secret_access_key and bucket_base_name. aws_access_key and aws_secret_access_key are the keys received at the time of creating an account with Amazon EC2 and bucket_base_name is the name of the bucket into which the data needs to be stored.

    • deploy.rb – This is the deployment file containing the Capistrano configurations for ec2onrails.

  • Start the instance of the image – The instance can be started as follows:

    • Signup for Amazon EC2 and S3 to acquire the necessary authentication credentials – The necessary authentication credentials are the privacy encoded mail security X509 certificate, privacy encoded mail security private key file and the account ID.

    • Installing the EC2 Tools – This basically involves no installation as such because all what is required is to get the tools downloaded from the EC2 site, unzip it into a folder. The unzipped files are the pre-installed files, hence to make the tools visible, an environment variable – EC2_HOME is set with the path to the EC2 tools folder. Apart from this we need to tell the tools for whom it is going to be used for by setting two more environment variables such as EC2_PRIVATE_KEY and EC2_CERT containing the paths of the private key file and X509 certificate.

    • Start running the instance – All what we are left now is with running the instance. In order to run the instance we need to do the following:

      • Find a suitable AMI(Amazon Machine Image) – This happens to be the crucial step. Why I say that this is a crucial one is because on executing the command: ec2-describe-images –o self –o amazon, it will list all the available images. We need to pick the most stable image that will suffice our purpose. This is where I initially went wrong. What I did was, I chose an image without reading the name of the image file, which happened to be a very unstable one and hence had to install all the required software manually which had dependencies issue and as a result of this I had to spend several additional hours in the setup process. But realized pretty early that I was in the wrong track and then chose the right one. So how do we choose the right image? In the listing we need to look for developer-image which is public and available and make a note of the ami ID(something like ami-xxxxxxxx).

      • Generating the key pair – The privacy enhanced mail security files is used for all the interactions with the image but each and every time we interact we need to use then in our command with various options. This can be avoided by generating key pair out of the two security files and use this key pair for all the usage. In order to generate the key pair execute the command: ec2-add-keypair <name>. The name can be anything and this list a key pair which needs to be stored in a file with the name of our choice.

      • Run the instance – On executing: “ec2-run-instance ami-xxxxxxxx key_pair_filename”, the instance starts running. But it takes long time to start. This is because Amazon EC2 moves the images around the network before they can be launched. For big images and/or congested networks, this takes several minutes. To improve performance, images can be cached. As you launch your images more frequently, it becomes less noticeable.

      • Authorize Network Access o the instance – The instance uses port 80 and 22 which can be authorized by executing: “ec2-authorize default -p 22” and “ec2-authorize default -p 80”. If your application requires nay other port for access, it can be done the same way.

  • Fetch the Public key – The Capistrano deployment requires the public key of the server which can be fetched by executing: “cap ec2onrails:get_public_key_from_server”

  • Finally deploy the application with Capistrano – Firstly setup the ec2onrails Capistrano deployment by saying, cap ec2onrails:setup and then the first deployment can be done by executing, cap deploy:cold and for the later successive deployments just use, cap deploy. Apart from this the Capistrano with ec2onrails provides cap ec2onrails:db:archive and cap ec2onrails:db:restore. They can be explicitly executed for archiving and restoring the data for the database. But on the cold deploy execution the ec2 instance starts the incremental archiving of the data using the predefined cron jobs.

We now have our application hosted on EC2. Yes, it is that easy.

The only question that one would have in his/her mind now is, what will happen if my instance or the ec2 server terminates? Once the server terminates, the instance is lost and can never be got back. This is one feature that ec2 lacks. But it provides a solution to handle such situation.

There is something called as bundling of the image. On bundling the image, the instance configuration and the application is uploaded to the S3 which can then be register to another instance and the application can be in form again. This can be achieved as follows:

Prepare for bundling – The server requires the two privacy enhanced mail security files. This can be got by using scp command.

Example - scp pk-xxyyzz.pem cert-xxyyzz.pem root@ec2-xx-xxx-xx-xxx.compute-1.amazonaws.com:/mnt -i keypair_file_name

Bundle the current image – From the ec2 instance bundle the image.

Example - ec2-bundle-vol -d /mnt -k /mnt/pk-xxyyzz.pem -c /mnt/cert-xxyyzz.pem -u account_number -r i386

Upload the AMI – The AMI is then uploaded to S3.

Example - ec2-upload-bundle -b bucket_name -m /mnt/image.manifest.xml -a access_key_id -s secret_access_key

Register the Uploaded image – The image needs to be register from the local system and can be done as: ec2-register bucket_name/image.manifest.xml

This gives an ami ID with which the instance can be run.

EC2 - a quick and cost effective way of hosting Web Applications.

Posted by relton, filed under Ruby On Rails. Date: July 23, 2008, 4:51 pm | 2 Comments »