Virtualizing Drupal Development Environment with Vagrant, Drush & Co

This post is a rip-off of my presentation from the last DrupalCamp Cebu entitled Virtualizing Drupal Development Environment. If you want to check some info of that presentation including the slides, please go here. All codes shown here are available on my GitHub repo drupal-vm.


Before going deep into the content, these are the tools that are used in this post with their brief functions:


  • VirtualBox
    • Hypervisor that creates and runs virtual machines (referenced as VM from hereunto)
  • Vagrant
    • Interacts with the hypervisor to create and run VMs from a config file
  • Ansible
    • Provisioning tool
    • Install and setup Apache
    • Install and setup MySQL and database related config & tasks
    • Install and setup PHP and PHP packages
    • Install and setup Composer
  • Drush
    • Drupal’s command line & shell scripting interface
    • Installs Drupal


When I started developing PHP applications, I only used XAMPP as my PHP development stack. It was pretty convenient to me back then because of the GUI and hey, it’s a one-click installer. I know lazy guys like you don’t probably want to use a tool that only works after entering several commands on a terminal and editing a bunch of configuration files on a Linux machine. Don’t worry, I was one, and I still am.

As I continue working from one project to another, I continuously encounter a lot of environment related issues until I couldn’t focus on the actual development anymore.
The issues

Some of these issues are the following:

  • Some tools are difficult to install. I can’t get to simulate the production environment on my local machine because some tools are difficult to install, others don’t even work at all. Sometimes when I install PEAR packages there are errors that would bring you to the deepest part of the internet when searching for solutions.
  • Some programs on my daily OS interfere with my development stack. The first one to this is Skype which is known to use ports 80 and 443 by default. If your XAMPP is configured to use port 80 by default and you have your Skype started ahead then you are in trouble. Although this is pretty easy to resolve once you know what’s interfering your Apache server. But there could be more programs on you daily OS that may interfere your development stack. What are those programs? Nobody really knows exactly as everyone have different setups.
  • It works on my machine. Some developers probably have uttered this words once or twice at a certain point in their life as developers. The main reason why this scenario occurs is your local development environment is very different from the production environment. Our local development environment should be as identical as possible to our production environment. That way, we’re eliminating every possible reason why this piece of code works on our local but not on the production.

The solution

Virtualization. This is the most efficient way to eliminate all those issues. And this can be achieved by using VirtualBox (or similar applications) and Vagrant. VirtualBox is pretty easy to use so we’ll skip that and proceed with Vagrant.

Vagrant is basically just a wrapper around virtualization applications such as VirtualBox. It enables you to create, update and destroy VMs through the use of a simple and easy to understand text file called Vagrantfile. A basic Vagrantfile usually looks like this:

# -- mode: ruby --

vi: set ft=ruby :

Vagrant.configure(2) do |config| = “ubuntu/trusty64” “private_network”, ip: “”

config.vm.synced_folder “./www”, “/var/www”, id: “vagrant-root”

#config.vm.provision “shell”, path:””, privileged: false


Where: = “ubuntu/trusty64” – lets you define the base image/box that you want to use for your VM. Base images are pre-packed minimal OS images that needs to be downloaded first before you can start creating a VM. Some base boxes can be downloaded from vagrantcloud or from vagrantbox. “private_network”, ip: “” – lets you define the networking you want your VM to use and assign specific IP.

config.vm.synced_folder “./www”, “/var/www”, id: “vagrant-root” – lets you define a shared folder between your host machine and your VM. This comes in handy when you want to edit codes directly from your host machine without accessing the VM.

config.vm.provision “shell”, path:”” – lets you do shell provisioning for your VM. Your script could contain some package installation commands to install necessary packages or some initialization commands needed for your app to work. This type of provisioning works well for basic tasks that doesn’t need a lot of configuration. But for tasks that needs a lot of configuration, you might wanna use other provisioning methods that uses more sophisticated tools such as Ansible which we will look at later.

Now that we have a basic Vagrantfile capable of creating a new VM, all we need to do is run the simple vagrant up command and our VM should be up and running.

bryancs@bryancs:/media/bryancs/Files/Drupal/demo$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'ubuntu/trusty64' is up to date...
==> default: A newer version of the box 'ubuntu/trusty64' is available! You currently
==> default: have version '20150422.0.1'. The latest is version '20151110.0.0'. Run
==> default: vagrant box update to update.
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 2201.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 => 2201 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address:
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
GuestAdditions 4.3.10 running --- OK.
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => /media/bryancs/Files/Drupal/demo
==> default: Machine already provisioned. Run vagrant provision or use the --provision
==> default: flag to force provisioning. Provisioners marked to run always will still run.

So we have our VM up and running, how do we access it? The only way to access your VM is through SSH by running the command vagrant ssh. But it only contains the bare OS from the base box that we downloaded. We have to install first all the stuff that we need such as web servers, database servers, php and other packages to start developing web applications. We could use the shell provisioning mentioned above but it’s not really the best option that we have. So we’ll use the other provisioning method called Ansible provisioning and use Ansible to provision our VM.


Ansible. Ansible is a simple and easy to use provisioning tool that uses ssh to communicate, install and configure stuffs on our VM. It also uses some configuration files in yml format and jinja templating tool which can be grouped together to form roles that performs a couple of tasks related to each other in order to install a single component of your stack (e.g. web server). A basic Ansible directory setup looks like this:

├── JJG-Ansible-Windows
│   ├── LICENSE
│   ├──
│   └──
├── playbook.yml
├── requirements.yml
├── roles
│   ├── apache-php
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │   └── virtualhost.conf
│   ├── composer
│   │   ├── files
│   │   │   └──
│   │   └── tasks
│   │   └── main.yml
│   └── drush
│   └── tasks
│   └── main.yml
└── vars
└── main.yml

Under the roles you will see apache-php which installs and configures apache & php and composer which installs composer. The database server (mysql) is configured inside the playbook.yml file and gets installed using a public role (geerlingguy.mysql) taken from Ansible-Galaxy. To get started with Ansible, I suggest you visit @geerlingguy’s article Ansible 101 – on a Cluster of Raspberry Pi 2s here. The same guy also wrote a book about Ansible called Ansible for DevOps available here.

Now we finally have come to the last portion and that is installing Drupal. You can opt to install Drupal manually but heck we already started automating things so why not go all the way? In order to automate Drupal’s installation we need a toold called Drush

Drush. Is a command line shell and scripting interface for Drupal. The recommended way to install Drush is through Composer which was installed for us by Ansible on one of the roles above. You might wanna ask why not install Drupal using Ansible? It is actually possible and in fact recommended but I wanted to show you how Vagrant’s shell provisioning works and I think Drupal installation suites the purpose well. Below is how the script looks like.


Install Drush via Composer

echo “Installing Drush using Composer…”
composer global require drush/drush

Install Drupal via Drush

echo “Installing Drupal…”
cd /var/www/
drush si -y –account-pass=admin!23 –db-url=mysql://drupal:28yYEyPCZfbV@localhost/drupal


composer global require drush/drush – Installs Drush globally via Composer
drush si -y –account-pass=admin!23 –db-url=mysql://drupal:28yYEyPCZfbV@localhost/drupal – Installs Drupal on the current working directory (/var/www/ via Drush. The CWD is inside the guest shared directory which contains a copy of Drupal.

Now that everything is setup, all you need is run vagrant reload –provision to reload your VM and run the provisioners.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: