
So you’ve done all the hard work. You’ve got a web server (Apache) complete with a reverse proxy balancer (mod_proxy), to serve requests to your rails back end (mongrel), that is going to hit a database (MySQL or Postgres) to generate pages for your users. You’ve even gone to the trouble of managing versions of your source code with Subversion. You know the site works on your local development machine, now it’s time to link all the pieces together up on the server and make it public.
First things first, lets make our lives even easy going forward by setting up capistrano to manage deploying our site, database, and any other associated tasks required on the remote server. No more SSH (well… almost), no more FTP, yay! Get the latest from the gem repository, on your local machine type:
sudo gem install capistrano -y
Now you need to go to the root directory of your rails application and type:
capify .
This will create the Capify and config/deploy.rb files that capistrano will read for your deployment tasks. Open up the config/deploy.rb file and edit the default entries to match what you have setup for your application and server, then paste the following tasks at the bottom (thanks to Shane and Pat Nakajima for some of the original code)
require 'rubygems'
require 'erb'
require 'bells/recipes/apache'
set :user, "deploy"
set :group, "deploy"
set :db_user, "app_user"
set :db_pass, "password"
# =============================================================
# Apache Settings
# =============================================================
set :apache_server_name, nil
set :apache_conf_path, "/usr/local/apache2/conf/sites"
set :apache_conf_file, "#{application}.conf"
set :apache_ctl, "/usr/local/apache2/bin/apachectl"
set :apache_server_aliases, []
# set :apache_ssl_enabled, false
# set :apache_ssl_ip, nil
# set :apache_ssl_forward_all, false
# set :apache_ssl_chainfile, false
# In the event you have the urge to develop your own vhost erb template, you can modify
# this variable. I wouldn't do it unless you're strongly confident in what you're doing.
set :apache_conf_template, 'http://footodo.com/open/tools/recipe/templates/vhost.conf'
before "deploy:setup", :db
after "deploy:update_code", "db:symlink"
after "deploy:setup", "db:create"
namespace :db do
desc "Create database yaml in shared path"
task :default do
db_config = ERB.new <<-EOF
base: &base
adapter: mysql
socket: /var/lib/mysql/mysql.sock
username: #{db_user}
password: #{db_pass}
production:
database: #{application}_production
<<: *base
EOF
run "mkdir -p #{shared_path}/config"
put db_config.result, "#{shared_path}/config/database.yml"
end
desc "Make symlink for database yaml"
task :symlink do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
end
# Making sure things will go smoothly.
depend :remote, :directory, apache_conf_path
depend :remote, :directory, deploy_to
depend :local, :gem, 'bells'
namespace :deploy do
namespace :apache do
desc "Setup vhost conf on Apache web server."
task :setup do
sudo "mkdir -p #{apache_conf_path}"
sudo "chown -R #{user}:#{group} #{apache_conf_path} && chmod -R 775 #{apache_conf_path}"
logger.info "generating .conf file"
conf = Net::HTTP.get URI.parse(apache_conf_template)
require 'erb'
result = ERB.new(conf).result(binding)
logger.info "putting #{application}.conf on #{domain}"
put result, "#{application}.conf"
run "mv #{application}.conf #{apache_conf_path}/#{apache_conf_file}"
end
end
# Overwritten to provide flexibility for people who aren't using Rails.
task :setup, :except => { :no_release => true } do
dirs = [deploy_to, releases_path, shared_path]
dirs += %w(system).map { |d| File.join(shared_path, d) }
run "umask 02 && mkdir -p #{dirs.join(' ')}"
end
# Also overwritten to remove Rails-specific code.
task :finalize_update, :except => { :no_release => true } do
run "chmod -R g+w #{release_path}"
end
end
And one last thing before I get into explaining what everything there does:
sudo gem install bells -y
Okay, so working backwards. The Bells gem is an add on for capistrano that takes care of certain tasks for us, such as restarting apache (I’ll likely change this in an upcoming post but if you’re following along in real time lets stick with how it is).
Our additions to the capistrano file provide us some methods to restart apache, create a new database.yml on the server and place it in shares/config/ so we don’t have to worry about other developers changing the config locally and breaking everything on deployment, and wrap the db:setup task with the extra features we’ve added. You may need to make sure that the paths to your application and the MySQL sock file are correct. Then save the files and ensure you’ve committed everything back into subversion. Now we can create the DB on the remote server:
cap db:setup