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 nodejs
sudo apt-get install nginx
sudo 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!
psql
ALTER USER Postgres WITH PASSWORD 'vagrant'; --run this in psql..I actually don't know why I had to do this.
\q --exit psql
exit
#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 rehash
bundle 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/bundle
and 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/bundle
and then runbundle install
again. (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 start
http://localhost:3000 should work now
http://localhost:8080 should show nginx welcome page
####Gemfile
gem 'unicorn'
bundle install
touch <app_root>/config/unicorn.rb
root = "/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.conf
upstream 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/default
sudo 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
;;
esac
chmod +x config/unicorn_init.sh
sudo 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" - vagrant
instead of just$CMD
- Try
sudo service unicorn_app_name start
andservice 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" - vagrant
TWO: 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"]
end
disclaimer: 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
Hi Josh, I'm followed these steps to the letter. But after step 18 (Symlink unicorn_init.sh), I try to start unicorn in my VM and I get this:
vagrant@lucid32:~$ sudo service unicorn start
env: /etc/init.d/unicorn: No such file or directory
yet in the previous step I had created said file....
Hopefully you can give me a hand with this issue, all my best. Didi
by the way I'm running on windows 8, perhaps that is the issue.