Follow Me Icons

 

Follow @KendrickColeman on TwitterConnect on LinkedInWatch My Videos on YouTubeFollow me on FacebookCheck Out My Projects on GitHubStay Up To Date with RSS

Search

Chef Cookbook and Recipe for Thin + Nginx with Rails

For simplicity, I deploy thinnginx for most of my rails applications. Thin is lighter weight than Passenger and the combo makes it more favorable than running Apache. I began learning Chef and saw nothing for thin existed so I attempted to make a cookbook.

 

If you don't want to read any more about this, then jump over to the code on github chef-thin_nginx.

 

This cookbook will install thin as a gem and complete a configuration. While 'nginx' will be installed from package and installed as a normal service.

 

To make the 'thin' installation from gem work properly, 'rvm' is required. rvm has a shell interface that is used to install the service from the gem. I previously tried to install thin from source and it wouldn't work correctly because 'rake' tasks are necessary gems that aren't loaded into the internal 'chef' gemset. In addition, I tried to install the thin gem to chef's internal gemset, but I received lots of errors when it came to postgresql gems. That is why rvm is necessary. rvm will install version 1.6.1 of thin unless you change the parameters. This was tested with 1.6.1 so it will work.

 

nginx, on the other hand, is a simple repository installation and will be installed as a service.

 

All of this was tested on Ubuntu 12.04.03 LTS and should be fine with 12.04.4 Precise Penguin.

 

Attributes

There is only one key attribute that is necessary to be changed and that is ['thin_nginx']['app_name']. This attribute should be changed to the application name (or folder name) that is being served. By default it's set to 'jumpsquares' because that is the project this was based off of. You can see that cookbook here and read more about the JumpSquares.net - a new kind of bookmark project.

 

Optional attributes such as:

  • ['thin_nginx']['user'] is the user that will run the webserver. 99% of the time this is www-data
  • ['thin_nginx']['number_of_thins'] will take an integer and spin up as many webservers as you define. The amount will also be added to nginx.conf files during the build
  • ['thin_nginx']['rails_env'] is to set any particular environment for thin to use in its configuration.
  • ['thin_nginx']['ruby_version'] is used to set a variable based on your default ruby version. This was tested with ruby-2.1.2.

 

I will not go over any other attributes. Check out the chef-thin_nginx github page to see them all.

 

To get it to work:

First you must have rvm installed. I think my earlier paragraph will make you understand. Second, you need to have your application resting in it's folder. Usually, this will be in '/var/www/myproject'. Make sure 'myproject' has it's contents filled with everything that it will need. Another point to mention is that this cookbook has only been tested with Rails projects. By default, the server template for nginx is set to the '/public' directory.

root <%= node['thin_nginx']['application_dir'] %>/public;

 

That's all. Put it in your run-list and have it. Here is a sample run-list that works.

Things not working:

For some odd reason I can't get the attributes to override from another cookbook. So if you're using this as an 'include' into another cookbook, be sure this is taken into account and perhaps upload this cookbook into multiple environments

 

The Recipe/Code (placing this here for giggles. Up to date code will ALWAYS be on chef-thin_nginx):

#this RVM shell will download the thin gem to your local RVM gemset
#then we will install the gem and create a configuration file
#the wrapper must be created to allow thin to boot at start
rvm_shell "install thin" do
  ruby_string "#{node['thin_nginx']['ruby_version']}"
  code %{
source #{node['thin_nginx']['rvm_source']}
gem install thin -v #{node['thin_nginx']['thin_version']}
rvmsudo thin install
/usr/sbin/update-rc.d -f thin defaults
rvmsudo thin config -C /etc/thin/#{node['thin_nginx']['app_name']} -c #{node['thin_nginx']['application_dir']} --servers #{node['thin_nginx']['number_of_thins']} -e #{node['thin_nginx']['rails_env']}
rvmsudo rvm wrapper #{node['thin_nginx']['ruby_version']} bootup thin
}
end
#we are changing the bootup environment to use our new wrapper
ruby_block "changing startup DAEMON for thin" do
original_line = "DAEMON=#{node['thin_nginx']['ruby_path']}/gems/#{node['thin_nginx']['ruby_version']}/bin/thin"
  block do
    daemon_file = Chef::Util::FileEdit.new("/etc/init.d/thin")
    daemon_file.search_file_replace_line(/#{original_line}/, "DAEMON=#{node['thin_nginx']['ruby_path']}/bin/bootup_thin")
    daemon_file.write_file
  end
end
#install nginx from package
apt_package "nginx" do
  action :install
end
#make necessary changes to our nginx.conf file
template '/etc/nginx/nginx.conf' do
  path "/etc/nginx/nginx.conf"
  source 'nginx.conf.erb'
  owner 'root'
  group 'root'
  mode 0644
  action :create
end
#make changes to our default site file
template "/etc/nginx/sites-available/#{node['thin_nginx']['app_name']}" do
  path "/etc/nginx/sites-available/#{node['thin_nginx']['app_name']}"
  source 'default0.erb'
  owner 'root'
  group 'root'
  mode 0644
  action :create
end
#create a symbolic link between two folder
execute "link thin" do
  command "ln -nfs /etc/nginx/sites-available/#{node['thin_nginx']['app_name']} /etc/nginx/sites-enabled/#{node['thin_nginx']['app_name']}"
end
#lets start the nginx service and give it some abilities to etc/init.d
service "nginx" do
  supports :status => true, :restart => true, :reload => true
  action [ :enable, :start ]
end
#this will start our webserver for first time use!
rvm_shell "start the webserver" do
  ruby_string "#{node['thin_nginx']['ruby_version']}"
  code %{
rvmsudo /etc/init.d/thin start
rvmsudo /etc/init.d/nginx reload
rvmsudo /etc/init.d/nginx restart
}
end