Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save duleorlovic/8815e439905dbd326a41 to your computer and use it in GitHub Desktop.
Save duleorlovic/8815e439905dbd326a41 to your computer and use it in GitHub Desktop.
Quickly deploy any Ruby on Rails application to VirtualBox using Vagrant or to any other provider of Linux machine just running this shell script

Deploy Ruby on Rails

You can use those bootstrap script to deploy your Rails application to Virtualbox. It's not intended to replace Chef or Puppet, but since its plain bash, its very readable and you can copy some lines and paste to your ssh session...

How to use

After installing Vagrant software run vagrant init and edit your Vagrantfile

# Vagrantfile
Vagrant.configure(2) do |config|
  config.vm.provider :virtualbox do |vb, override|
    # list of all machines can be found https://atlas.hashicorp.com/boxes/search
    override.vm.box = "ubuntu/trusty64"
    vb.customize ["modifyvm", :id, "--memory", "2048"]
    vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
    override.vm.network "forwarded_port", guest: 3000, host: 3000
    override.vm.provision :shell, path: 'vagrant/create_deployer_user_and_other_root_tasks.sh', keep_color: true
    override.vm.provision :shell, inline: 'sudo -i -u deployer /bin/bash --login -c "source /vagrant/vagrant/bootstrap_ruby_on_rails.sh"', keep_color: true
  end
end

then fork this repo and clone locally and simply run vagrant up

git clone https://gist.github.com/8815e439905dbd326a41.git vagrant
vagrant up

Config

  • read ruby version from .ruby-version file or from Gemfil or use ruby 2.0
  • projects environment secrets should be in .vagrant.env . Ignore this file in .gitignore if it contains private keys. It contains env variables that can change deployment process:
# .vagrant.env
export RAILS_ENV=production # use this if you want to run in production mode
export ADDITIONAL_PACKAGES="libmagickwand-dev libqtwebkit-dev" # if your project use gem rmagic and capybara-webkit 
export DATABASE_URL=postgresql://deployer@localhost/rails_db # this is default, but you can change to mysql2 adapter and other credentials
export DATABASE_EXTENSIONS="hstore " # if you use postgres hstore
export AWS_SECRET_ACCESS_KEY=123asd # export any third party keys

How to contribute

If you spot any errors, you can rerun script with vagrant provision | tee log/vagrant. Note about scripts:

  • script should be idempotent so you can provision it several times.
  • provision should stop on error since its set -e
    • does not stop in test commands, for example if [ some_error = "" ]; then echo yo;fi
  • it should work on Rails 3 and Rails 4
  • default is postgresql, but works for mysql as well, just put in your ~/.my_staging_secrets.yml
export ADDITIONAL_PACKAGES="mysql-server mysql-client libmysqlclient-dev"
export DATABASE_URL=mysql2://deployer@localhost/rails_db

If something is not working for you please write a comment so we can update the script. I tested with all projects from http://www.opensourcerails.com/

When you set up deployer password, you can ssh directly on VirtalBox :

ssh -p 2222 deployer@127.0.0.1

Windows

It should work on Windows as well. Just install VirtualBox, Vagrant and Railsinstaller .

If it is using a Hyper-V than you need to edit env variable. Start -> Computer (right click) -> Properties -> Advanced system settings -> Environment Variables Find system variable: VBOX_MSI_INSTALL_PATH and change its name to VBOX_INSTALL_PATH and value: C:\Program Files\Oracle\VirtualBox hashicorp/vagrant#3896

#!/bin/bash --login
# login argument is needed for rvm function
set -x # or set -v is used for debugging this script
set -e # Any subsequent commands which fail will cause the shell script to exit immediately
cd /vagrant
if [ "`grep DATABASE_URL /home/deployer/.profile`" = "" ]; then
echo STEP: some utility config in .bashrc and .profile
# bashrc is for interactive shell (it returns at beggining for sudo bash commands)
echo -e '\n# Some utility\n\
cd /vagrant\n\
export EDITOR=vim\n\
' >> ~/.bashrc
# .profile is for all shells
echo -e '\n\
# we will use database user deployer without password\n\
export DATABASE_URL=postgresql://deployer@localhost/rails_db\n\
export SECRET_KEY_BASE=`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 128 | head -n 1` # secret generated with https://gist.github.com/earthgecko/3089509\n\
# source my secrets (RAILS_ENV, AWS KEYS... overwrite of DATABASE_URL)\n\
[[ -s "/vagrant/.vagrant.env" ]] && source /vagrant/.vagrant.env\n\
' >> ~/.profile
fi
if [[ -f /vagrant/.ruby-version ]]; then
echo STEP: read ruby version from .ruby-version file
ruby_ver=`cat /vagrant/.ruby-version`
else
echo STEP: read ruby version from Gemfile
ruby_ver=$(awk '/^ruby/ { print $2 }' /vagrant/Gemfile | tr -d '"' | tr -d "'")
fi
if [[ $ruby_ver == "" ]];then
ruby_ver=2.1
fi
echo ruby_ver is $ruby_ver and currently is `which ruby`
if [[ ! '`which ruby`' == *"rvm"* ]] || \
[[ ! '`ruby --version`' == *$ruby_ver"p"* ]];then
echo STEP: install target ruby $ruby_ver
rvm install $ruby_ver
rvm use $ruby_ver --default
else
echo STEP: ruby $ruby_ver already installed
fi
if [[ -f /vagrant/.ruby-gemset ]]; then
echo STEP: .ruby-gemset is not supported because sudo -u deployer /bin/bash -c 'cd /vagrant && rvm current' does not see it, so removing it
rm /vagrant/.ruby-gemset
fi
echo STEP: install projects gems with bundle command
gem install bundler
bundle
echo STEP: create database
rake db:create
for db_extension in $DATABASE_EXTENSIONS ; do
# extension can be created only on existing database so we need to find database name
echo STEP: create postgresql $db_extension if not exists
if [ "`echo $DATABASE_URL`" == "" ]; then
echo STEP: DATABASE_URL not defined so use rails runner to get database name
database_name=`rails runner 'puts Rails.configuration.database_configuration["production"]["database"]'`
else
echo STEP: get database name from DATABASE_URL
database_name=`echo ${DATABASE_URL##*/}` # get the last string after / https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
fi
echo STEP: database_name is: $database_name
sudo -u postgres psql $database_name -c "CREATE EXTENSION IF NOT EXISTS $db_extension;"
done
echo STEP: seed
rake db:migrate
rake db:seed
echo STEP: precompile assets
rvmsudo -E rake assets:precompile # rvmsudo is needed because owner of files is vagrant, so deployer can't overwrite them
if [[ -f /vagrant/tmp/pids/server.pid ]]; then
echo STEP: stop current rails server
kill -9 `cat /vagrant/tmp/pids/server.pid` || rm /vagrant/tmp/pids/server.pid
fi
#rvmsudo -E rails s -p 80 -b 0.0.0.0 -d # rvmsudo is needed because port 80 requires sudo
rails s -b 0.0.0.0 -d
#echo STEP: start puma
#mkdir /shared # use outside of /vagrant since it has some problems with permissions on virtualbox
#chown deployer:deployer /shared
#sudo -u deployer mkdir -p /shared/pids /shared/sockets /shared/log
#cp /vagrant/config/puma.conf /vagrant/config/puma-manager.conf /etc/init
#echo "/vagrant" > /etc/puma.conf
#start puma-manager
#
#
#echo STEP: install and configure nginx
#apt-get install -y nginx
#ln -s /vagrant/config/nginx /etc/nginx/sites-enabled/default -f
#service nginx restart
#
#echo STEP: start unicorn
#service unicorn start
#
#echo STEP: start delayed job
#bin/delayed_job start
#if [[ `service unicorn status` == *"running"* ]];then
# echo STEP: stop existing unicorn service to save memory
# service unicorn stop
#else
# echo STEP: unicorn service already stoped
#fi
#
#echo STEP: load unicorn config
#. /etc/default/unicorn
#if [ "$DATABASE_URL" = "" ];then
# echo "STEP: configuring /etc/default/unicorn and /etc/unicorn.conf for database and ruby"
# echo -e "\nexport DATABASE_URL=postgresql://rails:$APP_DATABASE_PASSWORD@localhost" >> /etc/default/unicorn
# sed -i '/APP_ROOT/c APP_ROOT=/vagrant' /etc/default/unicorn
# # update PATH for new ruby
# sed -i "s/2.2.1/$ruby_ver/g" /etc/default/unicorn
# sed -i '/working_directory/c working_directory "/vagrant/"' /etc/unicorn.conf
# . /etc/default/unicorn
#fi
echo STEP: Done, Rails server started
echo STEP: $ vagrant ssh
echo "STEP: $ sudo kill -9 \$(cat /vagrant/tmp/pids/server.pid)"
echo STEP: visit your site at: http://`ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'`
#!/bin/bash
set -e # Any subsequent commands which fail will cause the shell script to exit immediately
set -x
update-locale LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 # needed for docs generation and database default
echo "STEP: update"
apt-get -y update # > /dev/null # this update is needed to set proper apt sources
if [ ! -f /swapfile ];then
echo STEP: creating swap
fallocate -l 256M /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# you can check with swapon -s
# make it permanent
echo '
/swapfile none swap sw 0 0
' >> /etc/fstab
else
echo "STEP: swap already exists"
fi
if [ "`id -u deployer`" = "" ];then
echo "STEP: creating user deployer"
useradd deployer -md /home/deployer --shell /bin/bash # adding user without password
gpasswd -a deployer sudo # add to sudo group
echo "deployer ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/deployer # don't ask for password when using sudo
if [ ! "`id -u vagrant`" = "" ]; then
usermod -a -G vagrant deployer # adding to vagrant group if vagrant exists
fi
else
echo "STEP: user deployer already exists"
fi
export DATABASE_URL=postgresql://deployer@localhost/rails_db
if [ -f /vagrant/.vagrant.env ];then
# get eventual ADDITIONAL_PACKAGES
source /vagrant/.vagrant.env
if [ ! "$ADDITIONAL_PACKAGES" = "" ]; then
export DEBIAN_FRONTEND=noninteractive #https://snowulf.com/2008/12/04/truly-non-interactive-unattended-apt-get-install/ this is needed to prevent mysql server root password prompt
apt-get -y install $ADDITIONAL_PACKAGES
fi
fi
if [ "`which git`" = "" ]; then
echo "STEP: install development tools"
apt-get -y install build-essential curl git nodejs
apt-get -y install libgmp-dev # this is needed for json
apt-get -y install libxslt-dev libxml2-dev # for nokogiri http://stackoverflow.com/questions/6277456/nokogiri-installation-fails-libxml2-is-missing
else
echo "STEP: development tools already installed"
fi
# DATABASE STUFF
if [ ! `echo $DATABASE_URL | cut -f 1 -d ':'` = "mysql2" ]; then
# postgresql is default
if [ "`which psql`" = "" ]; then
echo "STEP: installing postgres"
apt-get -y install postgresql postgresql-contrib libpq-dev
else
echo STEP: postgres already installed
fi
if [ "`sudo -u postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='deployer'"`" = "1" ]; then
echo STEP: postgres user 'deployer' already exists
else
echo STEP: create postgresql database user deployer
find /etc/postgresql -name pg_hba.conf -exec sed -i '/^local\s*all\s*all\s*peer/i # allow deployer to access without password - trust method\
host all deployer 127.0.0.1/32 trust' {} \;
# change md5 with trust, don't use this if you set up password for database user
/etc/init.d/postgresql restart
sudo -u postgres createuser --superuser --createdb deployer
fi
else
echo STEP: create mysql2 database user deployer
if [[ `echo "SELECT user FROM mysql.user WHERE user = 'deployer'" | mysql` = "" ]]; then
echo CREATE USER 'deployer'@'localhost' | mysql --user=root
echo GRANT ALL PRIVILEGES ON * . * TO 'deployer'@'localhost' | mysql --user=root
#FLUSH PRIVILEGES;
else
echo STEP: mysql user 'deployer' already exists
fi
fi
# check if rvm is installed
if [ "`sudo -i -u deployer type -t rvm`" != "function" ]; then
#if [ ! -f /usr/local/rvm/scripts/rvm ]; then
echo "STEP: installing rvm"
sudo -i -u deployer gpg --keyserver hkp://pgp.mit.edu --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 # --keyserver hkp://keys.gnupg.net
sudo -i -u deployer /bin/bash -c "curl -sSL https://get.rvm.io | bash -s stable --rails" # use this option for latest rails
else
echo "STEP: rvm already installed"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment