I am posting this as a compilation of resources I have come across since the guides out there don't cater for the virtualisation provided by Vagrant and the errors that can occur due to this.
As a result I will reference a lot of material as others have explained and formatted it better than I, while only replacing steps in said material such that it works under Vagrant.
In an actual deployment environment the resources linked are sufficient (this post is only for Vagrant):
You can either use Homebrew or the installers from their respective websites, here and here.
Via Homebrew:
brew cask install vagrant
brew cask install virtualbox
Vagrant boxes are images which are cloned into a virtual machine by Vagrant, we're going to use Ubuntu 14.04 from the Ubuntu repository to create our virtual machine.
vagrant box add ubuntu/trusty64
Vagrants default provider for virtualisation is VirtualBox so we don't have to configure anything on that front. All we need do is create a Vagrantfile
in or next to our projects root folder.
Vagrantfile
will serve as the 'location marker' for the /vagrant
folder inside our virtual machine, as such anything contained in same folder as our Vagrantfile
will be accessible inside our virtual machine.Make sure you cd
to wherever you want your shared directory to start from, then all we need to do is run vagrant init
with our Ubuntu 14.04 image.
vagrant init ubuntu/trusty64
Ta-da! We're now ready to boot and play around in our virtual machine.
To boot and then ssh into our virtual machine we must be in the same directory as our Vagrantfile
and run:
vagrant up
vagrant ssh
Now we're ready to install Ruby, Postgres, Rails, Unicorn, and Nginx.
Install rbenv
be sure to leave the file as .bash_profile
.Update apt-get, then install Postgres and it's dependencies:
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib libpq-dev
cd /vagrant
.Create Unicorn Init Script: Copy the supplied configuration, however:
USER
will always be vagrant
./home
from the APP_ROOT
path also leaving just /$USER/$APP_NAME
.Finally, given that ports under 1024 are privileged on OS X we're going to have to force our Rails application run on something higher so,:
CMD="cd $APP_ROOT && bundle exec unicorn -c config/unicorn.rb -E $ENV -D"
CMD="cd $APP_ROOT && bundle exec unicorn -c config/unicorn.rb -E $ENV -D -l 0.0.0.0:3000"
unicorn.sock
so amend the path to server unix:/home/tmp/sockets/unicorn.sock fail_timeout=0;
.root
configuration line make sure you replace deploy
for with vagrant
, producing: root /home/vagrant/APPNAME/public;
. proxy_pass
to http://localhost:3000;
.Since we changed the unicorn.sock
file location to a folder inside the /tmp/ folder (which will be deleted every time we halt
our machine) we're going to have to setup some shell provisions via vagrant to make sure that the command mkdir /tmp/sockets
is run every time we issue vagrant up
for this project.
Simply add the following under the configure
block in your Vagrantfile
anywhere you like:
# Create the /tmp/sockets folder we need every time on startup
config.vm.provision "shell",
inline: "mkdir /tmp/sockets"
Now instead of vagrant up
we must run vagrant up --provision
every time we wish to start our virtual machine and the /tmp/sockets folder will be created for us. If we don't make this folder Unicorn won't start!
At this point you should be able to access your application on http://localhost:8080/tasks
provided you have port forwarding setup in your Vagrantfile. Really though, you'll never access your application with a port on the end so we need to port forward and fix this. As mentioned before Vagrant cannot forward to ports under 1024 as they are privileged on OS X. Running Vagrant under sudo
does not help either as this privilege isn't passed to the VBoxManage process Vagrant spawns.
As a result we will forward ports 8080 on our host machine to the virtual machine (guest)'s port 80. Similarly, we shall forward all traffic on port 80 of our host machine to port 8080, also on our host machine. This way we can:
localhost
on our host machine...localhost:8080
on our host machine...localhost:80
on our guest (virtual) machine.Finally, we can access our application as localhost
!
The host machine is your physical machine, the guest is your virtual one. We're going to port forward port 8080 on the host to 80 on the guest.
Vagrantfile
and find the line with config.vm.network
in it.config.vm.network "forwarded_port", guest: 80, host: 8080
config.vm.network "forwarded_port", guest: 443, host: 8443
You've now port forwarded the default http and https ports from your host machine to the guest.
Now we need to map the host's ports 80 and 443 to the host's ports 8080 and 8443 so that vagrant can pick it up! We're going to use a nifty plugin called vagrant-triggers
because we don't want this taking place all the time. We only need it when we're running our Vagrant instance. Using vagrant-triggers
will allow us to execute commands on the host according to commands Vagrant is told to execute.
vagrant-triggers
by executing the following command in the same directory as your Vagrantfile
: vagrant plugin install vagrant-triggers
.Vagrantfile
inside the configure
block, anywhere you like.config.trigger.after [:provision, :up, :reload] do
system('echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
rdr pass inet proto tcp from any to any port 443 -> 127.0.0.1 port 8443
" | sudo pfctl -ef - > /dev/null 2>&1; echo "==> Fowarding Ports: 80 -> 8080, 443 -> 8443"')
end
config.trigger.after [:halt, :destroy] do
system("sudo pfctl -ef /etc/pf.conf > /dev/null 2>&1; echo '==> Removing Port Forwarding'")
end
Thus, running vagrant up
will setup the port mapping and running vagrant halt
will remove it.
You can now access your application from http://localhost/tasks
.
I hope this guide helps everyone. I had to go through a bit of hassle finding out information as to why this wasn't working under Vagrant specifically.
Huge thanks to DigitalOcean and this community whose members provided content for this guide including links to the pfctl
mapping under Yosemite and Unicorn socket configurations.
If you find anything wrong with the guide please message me so I can investigate and amend if required!
Happy coding,
tsujp
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With