SubReview image

User Login


Or OpenID




Register

Bookmark and Share SubReview
Add the SubReview review Feed

If you ever need to use Capistrano 2 with virtual hosts on Nginx this article may save you some time by automating the process.

The article assumes that for each vhost you want to define a nginx configuration file which gets placed in /etc/nginx/sites-available/ and symlinked to sites-enabled. If you just want one big nginx file with all your vhosts in it, then this article won’t help!

What we want is for Capistrano to auto generate the nginx configuration using a shared configuration template and place it on the server. E.g.

To get this working we need to do the following:
  • 1. Define some extra settings in our Capistrano deploy.rb file
  • 2. Create a nginx template on the server
  • 3. Create a Capistrano task to…
    • Get the nginx configuration template from the server
    • Get Ruby to parse the template using the values set in deploy.rb file.
    • Place the file back on to the server
    • Put the file in the sites-available directory and symlink to sites-enabled
  • 4. Create another task to generate the spin script using the correct port. There is more information about the spin script here.

1. Add some extra settings to deploy.rb

For this config I’m using multiple mongrels. If you’re not using mongrel then you can just add your own custom settings to be used in the template. Make sure you use different mongrel ports for each application. The extra settings are in red

set :application, “subreview.com”
set :domain, application # for use in the template

set :mongrel_port, 8500 # starting port for the mongrels
set :mongrels, 2 #number of mongrels

set :public_html, ”/home/demo/public_html/” # folder where the apps are deployed to
set :deploy_to, ”#{public_html}#{application}”

set :nginx_remote_template, ”#{public_html}nginx.template”
set :nginx_remote_config,”#{public_html}nginx.#{application}”

set :spin_remote_template, ”#{public_html}spin.template”
set :spin_remote_config, ”#{deploy_to}/current/script/spin”

2. Create the nginx template

Above I configured the shared nginx.template file to be held in home/demo/public_html (you could place it anywhere). Here’s the template file…



# File generated on <%=Time.now().strftime("%d %b %y")%>

#upstream name has to be unique so add on the port number

<%upstream="mongrels_#{mongrel_port}"%> 

#generate multiple mongrels
upstream <%=upstream %>{
    <%mongrels.times do |n| %>
        server 127.0.0.1:<%=n+mongrel_port%>;
    <% end %>
    }

# Redirect http://domain to http://www.domain

server {
            listen   80;
            server_name  <%=domain %> ;
            rewrite ^/(.*) http://www.<%=domain %> permanent;
           }

server {
            listen   80;
            server_name www.<%=domain %>;

            access_log <%=deploy_to%>/shared/log/access.log;
            error_log  <%=deploy_to%>/shared/log/error.log;

            root   <%=deploy_to%>/current/public/;
            index  index.html;

            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://<%=upstream %>;
                                           break;
                          }
            }

}


3. Create a Capistrano task to parse the template.

We need to download the template, parse it and put the new file back on to the server. As this is a generic thing to do, you can just create a ruby function and add it your deploy.rb file.



#
# Get the template from the server,
# parse it, and place the new file back on the server
# 
def RunTemplate(remote_file_to_get,remote_file_to_put)
    require 'erb'  #render not available in Capistrano 2

    get(remote_file_to_get,"template.tmp")      # get the remote file
    template=File.read("template.tmp")          # read it
    buffer= ERB.new(template).result(binding)   # parse it
    put buffer,remote_file_to_put               # put the result

end 



Then add a task called configure_nginx to deploy.rb


task :configure_nginx do

 # run the template  
 RunTemplate(nginx_remote_template,nginx_remote_config)

 #move the config in to sites-available
 sudo "mv #{nginx_remote_config} /etc/nginx/sites-available/#{application}" 

 #add a symlink into sites enabled 
 sudo "ln -s -f /etc/nginx/sites-available/#{application} 
 /etc/nginx/sites-enabled/#{application}" 

end


3.5 Test the task


cap configure_nginx


With any luck you should find a newly created file in /etc/nginx/sites-available/

4.Fix the spin script

If you have a spin script to start the mongrel servers
(/script/process) like this

home/demo/public_html/subreview.com/current/script/process/spawner -p 8000 -i 2 -e production

you’ll notice that the port and number of instances are hard coded. Once again we’ll need to make another template file.

Create a file called spin.template and place it in the public_html folder on the server (change the setting spin_remote_template in deploy.rb to change the location) . The template should look like this:


<%=deploy_to%>/current/script/process/spawner -p <%=mongrel_port%>
 -i <%=mongrels%> -e production


We also need to add another task to our deploy.rb file to process the template

task :configure_spin do

  RunTemplate(spin_remote_template,spin_remote_config)

end

It’s worth testing out the task with:



cap configure_spin 

Check the file your_app/current/script/spin on the server to make sure it has been updated. You may have to add an extra command to configure_spin task to make sure it has the correct permissions set.

Bringing it all together.

Add an extra line to the configure_nginx task to call configure_spin. Then set the configure_nginx task to be triggered when deploy:start or deploy:restart is called. You may want to change this so it occurs before a different deploy task.



task :configure_nginx do

 RunTemplate(nginx_remote_template,nginx_remote_config) 
  ......
  configure_spin 
end

before "deploy:restart","configure_nginx"  
before "deploy:start","configure_nginx" 


I also use another task called nginx_reload which is called after deploy, it’s detailed here.

If you now try cap deploy:cold it should go off and start your app (don’t forget to do cap deploy:setup if it’s your first time deploying it).

Notes

The custom tasks should really be put in to a separate file so you don’t have to duplicate them for each deploy.rb file.

If one of your domains needs some custom config in the nginx file, you can add something like this to the template



<% if domain="myspecial_domain" %>

... insert custom nginx config here

<%end %>

If you need help with Capistrano or nginx there are some good articles over at slicehost: nginx, capistrano.

Posted in Category::Ruby on Rails & Flex by sub1  04 Apr 08

You must log in to comment on this article


At some point when creating a Flex application you will want to update an item in the database using Rails(e.g. the details about a film).

To update a resource using REST you need to use the HTTP verb PUT, so the code below should work if we’re updating a film with ID=1:


<mx:HTTPService  id="UpdateFilm" 
           method="PUT"         
           url="films/1.xml" 
           useProxy="false" 
      ...
    </mx:HTTPService>


Unfortunately the above code doesn’t work, if you look in the rails logs you’ll find it’s doing a POST. HTTPService supports GET|POST|PUT|DELETE, but only if the useProxy is set to true (which means your using a Flex Data Services).

The manual states if useProxy=”false” you can only use GET or POST. Not particularly good if you want to get some rest in:-)

Luckily Rails has a work around for this, which is the detection of a _method parameter on the end of a URL. For example:



<mx:HTTPService  id="UpdateFilm" 
         method="POST"          
         url="films/1.xml?_method=PUT
         ....
</mx:HTTPService>

Posted in Category::Ruby on Rails & Flex by sub1  19 Mar 08

You must log in to comment on this article


SubReview was developed using Ruby on Rails v2, Flex and Yahoo YUI.

The software design behind the scenes is roughly based on a REST based architecture. If you’ve never heard of REST before then this site has a good explanation about it.

Some of the REST resources on this site are:

assets
articles
reviews

Posted in Category::Ruby on Rails & Flex by sub1  17 Mar 08

You must log in to comment on this article



Articles

Latest Film reviews
Daisy (데이지) 
Casshern (キャシャーン) 
SPL, Sha Po Lang (殺破狼) 
Sky Blue (원더풀 데이즈) 
R-Point (알 포인트) 
Latest Gadget reviews
Powerbar 
Philips Sonicare B400 Series (HX6431/46) 
FlashSticks 
Nokia N76 
Sony W880i 
Latest Game reviews
F1 2009 (Wii) (F1 2009) 
Resident Evil 4 (Wii Version) 
Latest Articles
OpenID now enabled by sub1  (06/05)
Why is GTA IV not on the Wii? by nicos  (12/04)
Capistrano Nginx Mongrel VHost by sub1  (04/04)
Flex HTTPService PUT method problem by sub1  (19/03)
SubReview development by sub1  (17/03)
Welcome by sub1  (11/03)


Bruce Lee Legendary Collection (Blu-ray) (Hong Kong Version)