Download and Install Vagrant http://www.vagrantup.com/ and VirtualBox https://www.virtualbox.org/ or VMware before beginning
#Set up Vagrant *this guide assumes the use of Mac OS X Mountain Lion on local machine and Ubuntu 12.04 LTS x64 on Vagrant box. It is compatible with many other distros but hasn't been tested.
##Step 1: Make and run box
vagrant init
vagrant box add <path to box directory or name according to https://vagrantcloud.com/>
vagrant up
vagrant ssh##Step 2: Forward ports ####Vagrantfile
config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 3000, host: 3000
#Set up environment You can choose to use configuration management/provisioning tools like Chef/Puppet for the following steps to set up your environment. But if you want to understand how it's done, I encourage you to do it manually.
##Step 3: Install needed system libraries and Postgresql
sudo apt-get update
sudo apt-get install git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev libcurl4-openssl-dev python-software-properties libpq-dev postgresql postgresql-contrib##Step 4: Install ruby
git clone git://github.com/sstephenson/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
exec $SHELL
rbenv install 2.1.0
rbenv global 2.1.0
rbenv rehash##Step 5: Install Bundler
echo "gem: --no-ri --no-rdoc" > ~/.gemrc
gem install bundler
rbenv rehash##Step 6: Install Node.js for Rails asset pipeline
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejssudo apt-get install nginxsudo su - postgres
createuser --pwprompt #create a role called vagrant.. just leave a blank password if you're using Vagrant locally for development and make it a superuser when prompted!
psqlALTER USER Postgres WITH PASSWORD 'vagrant'; --run this in psql..I actually don't know why I had to do this.
\q --exit psqlexit#Set up app
cd /vagrant #this is where your rails app should be by default if you changed it, just go to the right path on your VM
bundle install
rbenv rehashbundle exec rake db:create
bundle exec rake db:migrate- if there's encoding issues: https://gist.github.com/joshteng/9895494
- if you are facing cryptic errors (eg. wrong ELF class: ELFCLASS32) with bcrypt, pg etc+ gems just remove it from
/vendor/bundleand re-runbundle install - if the above still doesn't solve your problem, remove all the gems from your rails app by doing
rm -rf /vagrant/vendor/bundleand then runbundle installagain. (unfortunately this takes ages depending on your internet connection and rubygems.org) - if you're getting error
FATAL: role "vagrant" does not exist, you didn't do step 8 right
bundle exec rails s
sudo service nginx starthttp://localhost:3000 should work now
http://localhost:8080 should show nginx welcome page
####Gemfile
gem 'unicorn'
bundle install
touch <app_root>/config/unicorn.rbroot = "/vagrant"
app_name = "YOUR_APP_NAME"
working_directory root
pid "#{root}/tmp/pids/unicorn.pid"
stderr_path "#{root}/log/unicorn.log"
stdout_path "#{root}/log/unicorn.log"
listen "/tmp/unicorn.#{app_name}.sock"
worker_processes 4
timeout 40
preload_app true
# Force unicorn to look at the Gemfile in the current_path
# otherwise once we've first started a master process, it
# will always point to the first one it started.
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "#{root}/Gemfile"
end
before_fork do |server, worker|
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
# Quit the old unicorn process
old_pid = "#{server.config[:pid]}.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
puts "We've got an old pid and server pid is not the old pid"
begin
Process.kill("QUIT", File.read(old_pid).to_i)
puts "killing master process (good thing tm)"
rescue Errno::ENOENT, Errno::ESRCH
puts "unicorn master already killed"
end
end
end
after_fork do |server, worker|
port = 5000 + worker.nr
child_pid = server.config[:pid].sub('.pid', ".#{port}.pid")
system("echo #{Process.pid} > #{child_pid}")
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end- Starting unicorn:
bundle exec unicorn -c /vagrant/config/unicorn.rb -p 3000
#Set up Nginx
touch <app_root>/config/nginx.confupstream unicorn {
server unix:/tmp/unicorn.YOUR_APP_NAME.sock fail_timeout=0;
}
server {
listen 80 default deferred;
# server_name example.com;
root /vagrant/public;
try_files $uri/index.html $uri @unicorn;
location @unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
sudo ln -s /vagrant/config/nginx.conf /etc/nginx/sites-enabled/<your_app_name>sudo rm /etc/nginx/sites-enabled/defaultsudo service nginx restart- Start unicorn:
bundle exec unicorn -c /vagrant/config/unicorn.rb - Site should work at http://localhost:8080 now (make sure unicorn is still running)
#Make Unicorn a service for convenience
touch <app_root>/config/unicorn_init.sh
bundle install --binstubs #creates an executable in the bin directory for our unicorn_init shell script#!/bin/sh
set -e
# Example init script, this can be used with nginx, too,
# since nginx and unicorn accept the same signals
# Feel free to change any of the following variables for your app:
TIMEOUT=${TIMEOUT-60}
APP_ROOT=/vagrant
PID=$APP_ROOT/tmp/pids/unicorn.pid
CMD="$APP_ROOT/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb"
action="$1"
set -u
old_pid="$PID.oldbin"
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}
case $action in
start)
sig 0 && echo >&2 "Already running" && exit 0
echo "ATTEMPTING TO START UNICORN"
ruby -v
$CMD
# sudo su -c "ruby -v" - postgres
# sudo su -c "$CMD" - vagrant
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
upgrade)
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $old_pid && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $old_pid
then
echo >&2 "$old_pid still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
$CMD
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
exit 1
;;
esacchmod +x config/unicorn_init.shsudo ln -s <app_root>/config/unicorn_init.sh /etc/init.d/unicorn_your_app_name#shut down all instances of Unicorn (optional)
ps aux | grep unicorn #find unicorn processes
kill -9 <pid> #shut it down
#start up unicorn as a linux process
sudo service unicorn_your_app_name start #it's important to know which version of ruby will be used when running as different users. if you're facing errors, see below.#####If you're getting this error:
/opt/vagrant_ruby/lib/ruby/site_ruby/1.8/rubygems.rb:900:in "report_activate_error": Could not find RubyGem unicorn (>= 0) (Gem::LoadError)
Your init script isn't using the right version of Ruby. Here are few things you can try:
- Modify shell script to run your command as vagrant
su -c "$CMD" - vagrantinstead of just$CMD - Try
sudo service unicorn_app_name startandservice unicorn_app_name start
#####To debug effectively:
ONE: Check the version of Ruby that is being used when attempting to boot up Unicorn through your init shell script
#this is just a snippet of code in unicorn_init file
case $action in
start)
sig 0 && echo >&2 "Already running" && exit 0
echo "ATTEMPTING TO START UNICORN"
ruby -v #check the version of ruby you're using
$CMD
# sudo su -c "ruby -v" - vagrant #check the version of ruby you're using
# sudo su -c "$CMD" - vagrantTWO: Tail Unicorn log output to figure out what other erros you might have
tail -f /vagrant/log/unicorn.log#####Finally
if you're running unicorn as root, you will need to add root as a role for postgres (go through step 8 but add root instead of vagrant)
###Voila! It should work now!
#MISC
- Speeding up Vagrant: http://kubaf.wordpress.com/2013/01/12/vagrant-speed-up-on-mac-os-x/
- Add following in Vagrantfile
config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
enddisclaimer: I can't seem to get any of these solutions to speed up my VM. If you managed to speed up your VM on a Mac with VirtualBox, please leave some comment and help us out! Thanks!
In the meantime, you might want to look into VMware instead of VirtualBox