Wait, there could be a better way!
However this tutorial will give you a good insight as to how Vagrant works, and if you have an urge to know how things work behind the scenes (as I do), carry on reading.
Vagrant lets you configure a development environment in a virtual machine. You can then distribute this environment across platforms and team members. The good thing about that, is that the environment will be identical for everyone, thus ending the need for anyone to say ‘well, it works on my box’ ever again!
Well it works on my box
– Every developer, ever
Best of all, you don’t have even to login to the Virtual Machine (VM) that Vagrant creates. Your files remain on your host machine, so you can still edit them with your favorite text editor, and you will be able to use the browser on your host machine to view the development environment, thanks to all the clever routing that Vagrant puts in place.
For this guide we will get deep and dirty in command line, and even do some bash scripting, but don’t worry I’ll be right there to hold your hand, and explain what all those scary commands mean.
In this guide we are going to:
- Install Vagrant
- Install a Vagrant VM (Virtual Machine), called a ‘box’
- Install a simple LAMP (Linux, Apache, MySQL and PHP) stack on that box
- Install WordPress on the box
- View our WordPress installation by navigating to http://localhost:8080
Before we jump in, it is worth noting that I am using Mac OSX, so my examples will be targeted towards that particular Operating System. I’m also using iTerm 2 as my terminal program.
Vagrant needs to harness the power of virtualisation software. There are a few choices available, but because it is nice and free, we are going to use VirtualBox by Oracle. Fortunately for us we don’t have to get our hands dirty just yet. Just run the installer for your machine. While you are at it go ahead and install the extension pack from the same page.
Now to install the programme of the hour, Vagrant. Again, no mess, no fuss, just go get the Vagrant installer for the platform of your choice.
Ok, time to delve into that command line (hold my hand if you need to). First of all you will need to use the terminal to navigate to the root of your project (for example:
cd path/to/your/project), and run the following command:
That just created a file in the root of your project called ‘
Don’t worry about this file if you are using version control such as git, it is designed to be included as part of your project so that anyone working on the project will benefit from the same environment.
Go ahead, navigate to your project folder and take a look at the new
Vagrantfile. The file is written using Ruby syntax, but don’t worry about that, we are only going to tinker with it a little bit.
Get a box
I’m removing the comments for readability, but that script reads as follows:
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "base" ... end
VAGRANTFILE_API_VERSION = "2" sets a variable (to a string of 2). The line
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| passes the variable that was defined in the first line into the
Vagrant.configure() function. It also sets us up to ‘
do‘ stuff with the
config property of the
Vagrant.configure() function, until we
end it with the last line.
There is a line in the middle
config.vm.box = "base", and that is where we are going to do our tinkering.
First lets change the line
config.vm.box = "base" to:
config.vm.box = "precise32"
This means that we are going to be using the Linux distribution of Ubuntu 12.04.3 LTS (Precise Pangolin) (the 32 bit build). But we need to get that from somewhere. So look down your
Vagrantfile until you come across this commented out piece of code:
# config.vm.box_url = "http://domain.com/path/to/above.box"
Lets uncomment that file and change the path to:
config.vm.box_url = "http://files.vagrantup.com/precise32.box"
That line of code will go and grab that particular blend of Ubuntu, in a ready configured ‘box’, right from the Vagrant servers for us.
We are not done yet though. Keep hunting down the code until you find the following line, and go ahead and uncomment it:
# config.vm.network :forwarded_port, guest: 80, host: 8080
That line of code will forward port 8080 on your host machine to the standard port 80 on the box. So you will be able to go ahead and visit http://localhost:8080 and view your website.
Finally, in the commented
Vagrantfile you will notice a bunch of commented out things called provisions. One is for Chef, another for Puppet.
These are scripting languages that will let us install things onto our box after we have got it up and running. They are worth exploring in the future, but we are going to add our own ‘shell’ provision (yup, command line), because I think it is the simplest thing to get up and running with without us having to learn an extra load of syntax on top of what we are already doing.
At the bottom of the code, just before the
end, add the following line:
config.vm.provision :shell, :path => "provision.sh"
This means that we are going to use a shell script to install all the goodies that we need, and its path is in the root of our directory and is called ‘
We haven’t made that file yet, so in a moment we will go ahead and do that.
One more thing though, if you want to follow this tutorial to the bottom and install WordPress, those of you in the know will notice that WordPress has a habit of wanting to create files such as the
.wp-config.php file when it is running the installer. To allow WordPress to do this we are going to have to tinker with the permissions for the Vagrant synced folder (the root directory of our project within the Virtual Machine).
To do this add the following line of code before the
config.vm.synced_folder ".", "/vagrant", :mount_options => ['dmode=777,fmode=666']
This sets the default directory permissions (
777 which means that everyone has full control to the folder. It also sets the default file permissions (
666 which means everyone can read and write but not execute files.
Note to security experts: I am sure there is a nicer way to do this, and if so hit me up in the comments, but don’t worry too much, we can change these permissions in the
vagrantfile after our initial setup, and these changes will be implemented the next time we run
Vagrantfile (minus the comments) should now look a little like the following:
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "base" config.vm.box = "precise32" config.vm.box_url = "http://files.vagrantup.com/precise32.box" config.vm.network :forwarded_port, guest: 80, host: 8080 config.vm.provision :shell, :path => "provision.sh" config.vm.synced_folder ".", "/vagrant", :mount_options => ['dmode=777,fmode=666'] end
Shell script (building the LAMP stack)
In the root of your project make a new file called ‘
We are fortunate that PHP MySQL and Apache are all deployed with Ubuntu, so we don’t have to do any downloading before we install them, but what we do need to do is configure a password for MySQL before we can install it. To do this, add these two lines to
sudo debconf-set-selections <<< 'mysql-server-5.5 mysql-server/root_password password mypass' sudo debconf-set-selections <<< 'mysql-server-5.5 mysql-server/root_password_again password mypass'
These lines of code set the root password of MySQL (twice actually, an initial time and then again for confirmation) to ‘mypass‘ (you can change this to your choice of password).
In the code ‘
sudo‘ means do something as a super user, and
debconf-set-selections lets us set defaults in our Ubuntu config file (
debconf). The rest of the lines simply set the password and the confirmation for MySQL.
Now we can install our LAMP stack. To do that add the following lines of code to
sudo apt-get update sudo apt-get -y install mysql-server-5.5 php-pear php5-mysql apache2 php5
In the code above the
apt part of
apt-get stands for ‘Advanced Packaging Tool’. The command
apt-get update will make sure that the source list for the
apt-get tool is up-to-date.
The next line
sudo apt-get -y install mysql-server-5.5 php-pear php5-mysql apache2 php5 means that we are going to
install the packages
mysql-server-5.5 php-pear php5-mysql apache2 php5 using
-y means that we are going to automatically answer yes to any prompts that may come up.
Exposing the Vagrant folder
By default the box will go ahead and serve files from its
/var/www folder. That isn’t much good to us, because we want to be able to edit our files using our host machine. The files from our project directory (where your
Vagrantfile sits at the root of) is available at
/vagrant on the guest box.
To be able to expose these files when we hit http://localhost:8080 we need to make a symbolic link between the
/var/www folder and the folder that you want to be served (in most cases the
You don’t have to, but in I am actually going to create a
public directory within the
/vagrant folder that Apache will use to serve files. That way the project will be configured so that the script containing your root MySQL password is outside of that public directory and in the root
To do this, we need to enter the following code into the
if [ ! -h /var/www ]; then mkdir /vagrant/public rm -rf /var/www ln -s /vagrant/public /var/www a2enmod rewrite sed -i '/AllowOverride None/c AllowOverride All' /etc/apache2/sites-available/default service apache2 restart fi
What on earth does all that mean? Well, I’ll tell you. first of all we have an
if block of code.
That looks something like this:
if [...]; then ... fi
if whatever is in the square brackets
 is true
then do something, until you get to the end if statement (which for some reason is
fi in this language).
So what does that
if [ ! -h /var/www ] part of it mean? Well,
/var/www is the folder on the virtual machine that serves our web files. The
-h checks if the file exists and if it is a symbolic link (or a shortcut to another file, for those more familiar with that term). Finally the
! means not, so reverses a false to a true and vice versa. So basically the statement will be true if the file does not exist or is not a symbolic link (phew!).
Fortunately the next lines are a little bit simpler. The line
mkdir /vagrant/public simply means make the directory
/public within the
We then remove
rm the directory /var/www with the line
rm -rf /var/www sudo. The switches
-rf mean force this to happen without confirmation (
-r means remove any sub directories.
The magic happens with the line
ln -s /vagrant/public /var/www. This means make a link (
ln) that is symbolic (
-s) from the directory
/vagrant/public and call it
/var/www (essentially makes a shortcut). With this line of code, the files that are in our project folder (specifically the ones in the newly created
/public folder) will be served by apache when we hit http://localhost:8080.
a2enmod rewrite turns on the
rewrite module of Apache.
sed -i '/AllowOverride None/c AllowOverride All' /etc/apache2/sites-available/default edits (
sed is the stream editor command) the file
/etc/apache2/sites-available/default in place (with the
-i switch). It changes the line
AllowOverride Node to
AllowOverride All using a regular expression. We do this so that our Apache redirect can work.
Finally we restart Apache with the line
service apache2 restart.
We are putting our statements within the
if statement so that if we run the code
vagrant provision (to re-provision the Vagrant install) it doesn’t try to do all of the above again.
If you don’t want to use WordPress, you can go ahead and enter
vagrant up into your terminal window now, and whatever index file you put in your projects new
/public folder will will be there http://localhost:8080.
But, because we can, and because I love WordPress, lets get get the latest stable build of WordPress and put it in the
/public folder. To do this, you need to add the following lines of code to your
if [ ! -d /vagrant/public/wp-admin ]; then cd /vagrant/public wget http://wordpress.org/latest.tar.gz tar xvf latest.tar.gz mv wordpress/* ./ rmdir ./wordpress/ rm -f latest.tar.gz fi
This code is also wrapped in an
if statement. It checks that the directory
/vagrant/public/wp-admin does not exist (by using
! -d before it).
Once we are sure of that the file doesn’t exist, we change the directory (hey, that’s what
cd means, who knew?) to the
We then grab the latest stable release of WordPress from the URL
http://wordpress.org/latest.tar.gz with the command
We unzip it using
tar. The switch
x means overwrite any existing folders,
v means print the output to the terminal window, and
f means read from the file we specified (which in this case is
So far, the script will have put everything in a
/wordpress folder within the
/public folder. The next line moves (
mv) all the files within that folder (
wordpress/*) folder to the root of the current folder (
We now do a little bit of tidying up, by removing the WordPress directory by using
rmdir ./wordpress/ , and forcing the removal of the
.tar.gz file with the command
rm -f latest.tar.gz.
Creating the database
We are almost there. We just need to create our initial WordPress database so that we can install WordPress without much fiddling about on our new box. To do this run the following code:
if [ ! -f /var/log/databasesetup ]; then mysql -u root -pmypass -e "CREATE DATABASE wordpress;" mysql -u root -pmypass -e "CREATE USER 'mywpuser'@'localhost' IDENTIFIED BY 'mywppass';" mysql -u root -pmypass -e "GRANT ALL PRIVILEGES ON wordpress.* TO 'mywpuser'@'localhost';" mysql -u root -pmypass -e "FLUSH PRIVILEGES;" touch /var/log/databasesetup fi
The code above checks to make sure that a file called
/var/log/databasesetup does not exist with
We then run a few SQL commands with the keyword
mysql. The user is root which is entered by the line
-u root (
-u means user), and the password for root is the one we defined at the start of the
provision.sh script as
mypass (you may have entered your own root password), combine this with
-p (for password) making the command in this case
The part that lets us run our SQL commands is the
-e which essentially means echo the following SQL string into the
I will not explain all the SQL to you in detail, but a quick summary of what we are doing in this part is as follows:
- Create a database called ‘wordpress‘
- Crease a user called ‘mywpuser‘ with the password ‘mywppass‘
- Give all privileges to the database ‘wordpress‘ to ‘mywpuser‘
- Flush out the previlages
The final line
touch /var/log/databasesetup will create the file specified.
Putting it all together
provision.sh script should look a little something like the following:
sudo debconf-set-selections <<< 'mysql-server-5.5 mysql-server/root_password password mypass' sudo debconf-set-selections <<< 'mysql-server-5.5 mysql-server/root_password_again password mypass' sudo apt-get update sudo apt-get -y install mysql-server-5.5 php5-mysql apache2 php5 if [ ! -h /var/www ]; then mkdir /vagrant/public rm -rf /var/www ln -s /vagrant/public /var/www a2enmod rewrite sed -i '/AllowOverride None/c AllowOverride All' /etc/apache2/sites-available/default service apache2 restart fi if [ ! -d /vagrant/public/wp-admin ]; then cd /vagrant/public wget http://wordpress.org/latest.tar.gz tar xvf latest.tar.gz mv wordpress/* ./ rmdir ./wordpress/ rm -f latest.tar.gz fi if [ ! -f /var/log/databasesetup ]; then mysql -u root -pmypass -e "CREATE DATABASE wordpress;" mysql -u root -pmypass -e "CREATE USER 'mywpuser'@'localhost' IDENTIFIED BY 'mywppass';" mysql -u root -pmypass -e "GRANT ALL PRIVILEGES ON wordpress.* TO 'mywpuser'@'localhost';" mysql -u root -pmypass -e "FLUSH PRIVILEGES;" touch /var/log/databasesetup fi
To get it all working, in your terminal program, you need to
cd to your project root directory (the place where you ran
vagrant init), and enter the following command:
You may have to wait a while, and there will be a lot of output. But eventually you will end up with an output similar to the following:
That last bit of output was the unzipping of the WordPress files.
Now go ahead and navigate to http://localhost:8080 with your usual browser. Sure enough, there is our WordPress installer screen waiting for us to configure WordPress with our newly created username and password.
This guide really only scratches the surface of what is possible with Vagrant. At Make Do we use Vagrant in all of our projects to enable us to quickly get up and running with a per-configured environment.
Stopping and starting
You should of course go read up on Vagrant to learn some more commands, but before you go I will give you a couple of pointers that should keep you busy for a while.
You can stop your VM at any time by going to your project folder and entering the command
vagrant halt in your terminal.
If you have really really had enough, you can get rid of Vagrant by going to your project folder and typing
vagrant destroy. By using the script that I have provided, none of your files will be deleted (but you will lose all of your WordPress SQL data). This means you will still have that
/public folder in your project.
Start Vagrant again at any time by going to your project folder and entering