Deploying your rails app on slicehost with git (github), nginx virtual host, and thin
UPDATE July 13, 2008: see the very bottom for deploy.rb file that includes cron job and namespaces some of the deploy tasks.
–
This article assumes you already have git nginx, and thin setup properly on your slicehost. To get those going I recommend reading their articles at articles.slicehost.com, and browse their forum for git installation.
0. Make sure you server is setup to talk to github. Github has a guide
1. Capify your rails app from inside the root of your app in terminal
capify .
2. Edit the deploy.rb file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # here is a good standard example set :application, "undertakerapp" # Change this appropriately depending on what site you are testing set :domain, "domain.com" # your domain.com for this app set :user, "username" # your username on slicehost #from http://github.com/guides/deploying-with-capistrano default_run_options[:pty] = true set :repository, "git@github.com:scottmotte/motte_cms.git" # your repository. this could be anywhere, but i recommend github set :scm, "git" set :scm_passphrase, "password" #github password set :user, "username" #github username set :branch, "master" #this is the branch you want. most likely master set :deploy_via, :remote_cache #from hostingrails.com/forums/wiki_thread/46 set :use_sudo, false set :port, 8000 # your port on slicehost. Standard port for ssh is 22, but if you followed the slicehost articles, you probably changed this to something different set :deploy_to, "/home/#{user}/public_html/#{application}" # Where on the server your app will be deployed set :chmod755, "app config db lib public vendor script script/* public/disp*" # Some files that will need proper permissions # If you aren't deploying to /u/apps/#{application} on the target # servers (which is the default), you can specify the actual location # via the :deploy_to variable: # set :deploy_to, "/var/www/#{application}" # If you aren't using Subversion to manage your source code, specify # your SCM below: # set :scm, :subversion role :app, domain role :web, domain role :db, domain, :primary => true desc "Reload Nginx" task :reload_nginx do sudo "/etc/init.d/nginx reload" end desc "Restart Thin" task :restart_thin do sudo "/etc/init.d/thin restart" end after "deploy", "deploy:cleanup" after "deploy:cleanup", "reload_nginx" after "reload_nginx", "restart_thin" |
3. Fix up your database.yml: make sure the production database settings are specified as follows
1 2 3 4 5 6 7 | production: adapter: mysql encoding: utf8 database: yourapp_production username: mysql_user # the mysql username you are going to use. this could be root, but it probably isn't the best idea to use root password: password # the mysql password you are going to use. socket: /var/run/mysqld/mysqld.sock |
4. Setup your database on slicehost: This is easy(er) if you have phpmyadmin. To do it in the terminal do the following.
- ssh into your slicehost
- type mysql -u mysql_user -p (replace mysql_user with your mysql user. this could be root)
- a successful entering should show you the mysql> prompt (mysql>)
- type show databases;
- if it has not been created do
CREATE DATABASE yourapp_production;
5. Exit your server and go back to your local command prompt and cd inside your railsapp. Type the following:
1 2 3 4 5 6 7 8 | cap deploy:setup # wait for that to complete then... cap deploy:cold # wait for that to complete then you might need to do... cap deploy:migrations # any other changes you commit to github and then want to deploy, you can now just run 'cap deploy' (unless you have new migration files, in which case run 'cap deploy:migrations') |
6. Thin configuration:
Follow some of these steps to get thin setup, and your app symlinked
ssh into your slicehost
cd ~/public_html/railsapp/current folder
sudo thin config -C /etc/thin/railsapp.yml -c /home/username/public_html/railsapp/current/ --servers 3 -e production
IMPORTANT NOTE: If you are doing a second app on the same server through vhosts (like so) I’m pretty sure you need to change the default port in the the thin config file. 3000 will already be used by the original one you created.
Therefore, you might do something like this:
sudo thin config -C /etc/thin/railsapp.yml -c /home/username/public_html/railsapp/current/ --servers 3 --port 3001 -e production
check it exists:
cat /etc/thin/railsapp.yml
start it up:
sudo /etc/init.d/thin start
7. Nginx virtual host:
Add your site to the sites available
sudo nano /usr/local/nginx/sites-available/domain.com
Add server vhost and server info (Take your time doing this. There are a lot of places you could mistype things.)
upstream domain1 { server 127.0.0.1:3003; server 127.0.0.1:3004; server 127.0.0.1:3005; } server { listen 80; server_name www.domain.com; rewrite ^/(.*) http://domain.com permanent; } server { listen 80; server_name domain.com; access_log /home/demo/public_html/railsapp/shared/log/access.log; error_log /home/demo/public_html/railsapp/shared/log/error.log; root /home/demo/public_html/railsapp/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://domain1; break; } } }
Now enable it.
sudo ln -s /usr/local/nginx/sites-available/domain.com /usr/local/nginx/sites-enabled/domain.com
8. Now do another of these on your local computer:
cap deploy
UPDATE:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | set :application, "mottemen" # Change this appropriately depending on what site you are testing set :domain, "mottemanagers.com" set :user, "***username***" #from http://github.com/guides/deploying-with-capistrano default_run_options[:pty] = true set :repository, "git@github.com:scottmotte/mottemen.git" set :scm, "git" set :scm_passphrase, "***password***" #This is your custom users password set :user, "***username***" set :branch, "master" set :deploy_via, :remote_cache #from hostingrails.com/forums/wiki_thread/46 set :use_sudo, false set :port, 1984 set :deploy_to, "/home/#{user}/public_html/#{application}" # Where on the server your app will be deployed set :chmod755, "app config db lib public vendor script script/* public/disp*" # Some files that will need proper permissions role :app, domain, :cron => true role :web, domain role :db, domain, :primary => true namespace :cron do task :start, :roles => :app, :only => {:cron => true} do cron_tab = "#{shared_path}/cron.tab" run "mkdir -p #{shared_path}/log/cron" require 'erb' template = File.read("config/cron.erb") file = ERB.new(template).result(binding) put file, cron_tab, :mode => 0644 # merge with the current crontab # fails with an empty crontab, which is acceptable run "crontab -l >> #{cron_tab}" rescue nil # install the new crontab run "crontab #{cron_tab}" end end namespace :cron do task :stop, :roles => :app, :only => {:cron => true} do cron_tmp = "#{shared_path}/cron.old" cron_tab = "#{shared_path}/cron.tab" begin # dump the current cron entries run "crontab -l > #{cron_tmp}" # remove any lines that contain the application name run "awk '{if ($0 !~ /#{application}/) print $0}' " + "#{cron_tmp} > #{cron_tab}" # replace the cron entries run "crontab #{cron_tab}" rescue # fails with an empty crontab, which is acceptable end # clean up run "rm -rf #{cron_tmp}" end end namespace :nginx do desc "Reload Nginx" task :reload do sudo "/etc/init.d/nginx reload" end end namespace :thin do desc "Restart Thin" task :restart do sudo "/etc/init.d/thin restart" end end after "deploy", "deploy:cleanup" after "deploy:cleanup", "nginx:reload" after "nginx:reload", "thin:restart" after "thin:restart", "cron:stop" after "cron:stop", "cron:start" |

Scott | August 23, 2008
http://articles.slicehost.com/2008/7/10/mysql-creating-and-editing-users use that to create the users - instead of using the root user.
Millisami | October 22, 2008
@Scott,
where’s that #{shared_path} var set to??
scott | October 22, 2008
@Millisami - shared path gets set automatically by capistrano to your apps shared folder. So in this case it was ~/apps/undertakerapp/shared
Millisami | October 23, 2008
@scott - Thanks for the reply.
One more thing I forgot to ask about is the cron.
Why “namespace :cron do” is in 2 namespace blocks and what its really doing?
scott | October 23, 2008
Yea, actually, you could put the stop and start tasks inside the same cron namespace. I don’t know why I put them separately. Didn’t really know what I was doing at the time I suppose. =)
Also, just realized my blog strangled the > sign so everywhere you see > it should be the actually greater than sign >.