Supercharged PHP development with Vagrant, VMware, and IntelliJ IDEA

In my development environment I’ve been using Vagrant with Virutalbox for a while now; however, even with NFS, with the VM properly provisioned with enough resources, and running under Linux, the environment’s performance was still just barely tolerable. It’s performance compared to Ubuntu natively on a Samsung 850 pro SSD left me wishing for more.. A lot more.. 🙂

This tutorial will show you how to create a high performance PHP (or any language really) development environment using the JetBrains IntelliJ Idea IDE (with the PHP plugin), Vagrant 1.8.1 (latest version as of this post), VMware Workstation Pro 12, and good ole Ubuntu Trusty (14.04.3 with the vivid HWE stack). 😀 We will be using the vivid 3.19.43 kernel.

We also will be using native PHP 5.5.9 (but php-fpm, PHP 7, or HHVM would be even more awesome 😀 ) and XDebug as our remote debugger.

**Note: This tutorial assumes you have Vagrant, VMware, and Jetbrains IntelliJ Idea already installed and functioning on your host OS. It also assumes you already know how to install a guest OS in VMware.

This tutorial will be structured:

  1. First update/install all necessary Ubuntu packages in the VM.
  2. Configure our VM according to Vagrant standards.
  3. Configure Xdebug for Apache (although Nginx is a similar process).
  4. Turn our newly configured Ubuntu Virtual Machine into our own Vagrant base box with VMware as the provider.
  5. Configure our JetBrains IntelliJ Idea IDE (PHPstorm will work also) to work with our remote PHP interpreter and remote Xdebug debugger running in the VM.
  6. Lastly we will benchmark our VM development environment’s performance using wrk.

We have a lot to do… So… Let’s get started! 😀

**Note: This tutorial will use VMware Workstation 12 (but other VMware versions will probably work as well).

**Note: This tutorial also assumes you have a valid Vagrant VMware plugin license in order to interface Vagrant with VMware Workstation.

First do a minimal install of Ubuntu Trusty as a guest OS Virtual Machine using VMware Workstation.

If you don’t know how to do that, there are many tutorials available.

Pick one, install Ubuntu 14.04, and then come back. 🙂

**Note: When you install Ubuntu, since we’re creating a Vagrant base box, it is usually best to follow the Vagrant standard.

If you plan to share your base box with the public, using the Vagrant insecure settings is the standard way to configure it. This means the user should be vagrant with password vagrant, and the root password should be set to vagrant as well.

However, if this base box is only for your team and you don’t want it to be shared with anyone outside of your organization, then obviously the standard settings should be set to something much more secure.

OK….. So….. 🙂

At this point you should now have a minimal install of Ubuntu 14.04.3 (14.04.2 is fine also).

We’re now going to update the system, install the Ubuntu HWE stack, and then install all necessary packages for our LAMP stack and Vagrant Base Box.

Update repos and install/upgrade Packages:

vagrant@trusty:~$ sudo apt-get update

vagrant@trusty:~$ sudo apt-get install --install-recommends

vagrant@trusty:~$ sudo apt-get install build-essential libssl-dev

Upgrade Trusty to the LTS Enablement Stack:

// upgrade for better hardware support
// assumes using packages that are Multi-Architecture (both 32 and 64 bit)
vagrant@trusty:~$ sudo apt-get install --install-recommends linux-generic-lts-vivid xserver-xorg-core-lts-vivid xserver-xorg-lts-vivid xserver-xorg-video-all-lts-vivid xserver-xorg-input-all-lts-vivid libwayland-egl1-mesa-lts-vivid libgl1-mesa-glx-lts-vivid libgl1-mesa-glx-lts-vivid:i386 libglapi-mesa-lts-vivid:i386

At this point, if everything went well, you should be on the 3.19.0-43-vivid kernel.

Let’s check…

Check the kernel:

vagrant@trusty:~$ uname -r

The output should be…


vagrant@trusty:~$ 3.19.0-43-generic

Next, let’s install our LAMP stack.

Install the LAMP stack

vagrant@trusty:~$ sudo apt-get install apache2

vagrant@trusty:~$ sudo apt-get install mysql-server php5-mysql

// install php and any other php modules you need
vagrant@trusty:~$ sudo apt-get install php5-common php5-dev php5-cgi php5-cli php5-curl php5-xdebug php5-dbg php5-gd php5-mcrypt php5-oauth php5-memcache php5-redis php5-mongo libapache2-mod-php5

Next let’s make sure our NFS client is installed since we want Vagrant to spin up our VM using NFS (just like in Virtual Box) for greater performance.

Install NFS Client

vagrant@trusty:~$ sudo apt-get install nfs-common

Next, make sure you install any other packages you need in your stack.

Maybe you need Node? Mongo? Full MEAN stack? Redis? Java? Python? Ruby? Puppet/Chef?

Install any language, RDBMS, NoSQL DB, framework, or any platform that you need for you tech stack. Since our base box will be our template VM, we don’t want to have to install anything after it is created.

Lastly let’s install wrk so we can benchmark our HTTP requests. But first, let’s make sure git is installed and if it isn’t, we want to install it.

Install Git

vagrant@trusty:~$ sudo apt-get install git

Now let’s install wrk.

Install Wrk

vagrant@trusty:~$ cd /opt

// clone the github repo
vagrant@trusty:/opt$ git clone https://github/wg/wrk.git

vagrant@trusty:/opt/wrk$ cd ./wrk

vagrant@trusty:/opt/wrk$ make

// lastly add the exe to our env var PATH
vagrant@trusty:~$ cp wrk /usr/local/bin

Now we want to start configuring everything…

Let’s first configure our VM according to the Vagrant Base Box standard.

Since we’ve already created a user with a user/password combo as vagrant/vagrant and root has the password vagrant, the first step is done.

Next, we don’t want to be asked for a password when using sudo.

Let’s fix that.

Password-less Sudo

vagrant@trusty:~$ visudo

// append to the end and comment out any line containing "requiretty"

Now we want SSH to be fast, so let’s make sure “UseDNS” is set to “no”

Check UseDNS

vagrant@trusty:~$ cd /etc/ssh

vagrant@trusty:/etc/ssh$ sudo vim ssh_config

// append "UseDNS no" to the file if its not already contained
UseDNS no

Next up, let’s create the insecure public key the Vagrant will look for so Vagrant can log us in with our key instead.

Set our insecure public key for the user Vagrant

// make sure we're in home
vagrant@trusty:~$ cd ~

vagrant@trusty:~$ ls -la

// create .ssh directory if .ssh does not exist in /home/vagrant
vagrant@trusty:~$ mkdir .ssh

// change .ssh to permission 0700
vagrant@trusty:~$ sudo chmod -rf 0700 .ssh

// create the insecure vagrant public key
vagrant@trusty:~$ cd .ssh

vagrant@trusty:~/.ssh$ vim authorized_keys

// paste into our authorized_keys file
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key

Now we need to make sure our authorized_keys file has the correct permissions.

Set Permissions

vagrant@trusty:~/.ssh$ sudo chmod 0600 ./authorized_keys

Next, up let’s enable and configure Xdebug and while we’re at it, let’s also enable mod_rewrite.

Enable Rewrite Module

// enable mod_rewrite
vagrant@trusty:~$ sudo a2enmod rewrite

Now let’s configure Xdebug.

Configure XDebug Module

vagrant@trusty:~$ cd /etc/php5/apache2/conf.d

**Note: If the symlink for xdebug.ini isn’t in conf.d, symlink the config file xdebug.ini from /etc/php5/mods-available/20-xdebug.ini to /etc/php5/apache2/conf.d/20-xdebug.ini

// configure xdebug
vagrant@trusty:/etc/php5/apache2/conf.d$ sudo vim 20-xdebug.ini

// add to xdebug.ini

Next up, let’s configure a Vhost to be used as a template. Our Vhost will point to our NFS shared directory between our host and guest OS.

Create Vhost template

vagrant@trusty:~$ cd /etc/apache2/sites-available

vagrant@trusty:/etc/apache2/sites-available$ sudo vim vagrant-dev.conf

// Add these contents
< VirtualHost *:80>
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/vagrant_error.log
    CustomLog ${APACHE_LOG_DIR}/vagrant_access.log common

    # uncomment if using php-fpm
    #ProxyPassMatch ^/(.+\.(php)(/.*)?)$ fcgi://$1

    # don't use these settings in prod
    < Directory /var/www/html>
        AllowOverride all
        Options MultiViews Indexes FollowSymlinks
        Require all granted

        # not necessary if elsewhere or in .htaccess
        < IfModule mod_rewrite.c>
            RewriteEngine On
        < /IfModule>
    < /Directory>
< /VirtualHost>

Now we want to enable our vagrant-dev.conf vhost.

vagrant@trusty:~$ sudo a2ensite vagrant-dev.conf

Now let’s symlink our “html” directory to our soon to be Vagrant’s default shared directory.

**Note: You can point the vhost’s document root directly to the shared directory also.

Symlink to Shared Directory

vagrant@trusty:/etc/apache2/sites-available$ cd /var/www

vagrant@trusty:/var/www$ sudo ln -s /vagrant_data html

Next, since we don’t want to run a DNS server for a development environment, let’s manually point to this vhost.

Edit /etc/hosts

vagrant@trusty:/var/www$ cd /etc
vagrant@trusty:/etc$sudo vim hosts

// Add to your hosts file

That should be it for our VM configuration!

Now shutdown the VM, and let’s turn it into a base box with VMware Workstation as the provider.

Now we’re back on our host OS.

Navigate on the host OS, to the directory where your Virtual Machine is stored.

Navigate to Base box directory

dlaroche@laptop-dev:~$ cd baseboxes/Ubuntu-trusty

There should be files with extensions .nvram, .vmdk, .vmsd, .vmx, .vmxf, and some log files.

We need to first create a metadata.json file that Vagrant will read when creating the base box. This file can be detailed, containing provider and versioning info, but we are only going to use the bare minimum for this tutorial. You can learn more on the Vagrant site for more info on base box meta data, since this probably doesn’t meet your organization’s needs.

Create Vagrant metadata.json

dlaroche@laptop-dev:~/baseboxes/Ubuntu-trusty$sudo vim metadata.json

// Add to the file
  "provider": "vmware_workstation"

Now lets finally create the base box! 😀

We want to tar all of the files in the VM directory into a .box archive.

Create VMware Base Box

dlaroche@laptop-dev:~/baseboxes/Ubuntu-trusty$ tar cvzf ./*

Now that we have our VM as a base box, let’s now add it to Vagrant.

Add Base Box to Vagrant

dlaroche@laptop-dev:~/baseboxes/Ubuntu-trusty$vagrant box add our-organization/ubuntu-trusty

Now let’s take a look at our list of base boxes.
List Base Boxes added to Vagrant

dlaroche@laptop-dev:~/baseboxes/Ubuntu-trusty$vagrant box list

Now let’s configure our Vagrant init file, by going to the root directory of our code.

Create Vagrantfile

dlaroche@laptop-dev:~$cd workspace/test

dlaroche@laptop-dev:~/workspace/test$vagrant init 

Now add to your code’s Vagrantfile inside “Vagrant.configure” the following.

Add to Vagrantfile = "larochetech/ubuntu-14.04.3_64"
config.ssh.insert_key = false
config.vm.provider "vmware_workstation" "forwarded_port", guest: 80, host: 8080

// we configured xdebug to communicate to this network "private_network", ip: ""

// use nfs for greater performance
config.vm.synced_folder ".", "/vagrant_data", nfs: true

// Give the vm all of your cores and half of your ram.
// Setting the gui to true allows us to see the VM running
// in VMware. If you don't care about that, you can leave 
// it out.
config.vm.provider "vmware_workstation" do |v|
    v.gui = true
    v.memory = 8192
    v.cpus = 4

Now let’s edit our host OS hosts file to point to Vagrant.

Edit /etc/hosts

dlaroche@laptop-dev:~/workspace/test$ sudo vim /etc/hosts

// Add to your hosts file the private network of your VM

Now let’s spin up our VM using vagrant! 😀

Start VM through Vagrant

dlaroche@laptop-dev:~/workspace/test$ vagrant up

Since this is the first time the VM is spun up, Vagrant should provision it according to the VagrantFile settings, and if everything goes according to plan, you should have the VM running in VMware! 😀

Now that the VM is running under Vagrant… Finally… We’re ready to configure our IDE! 😀

Launch JetBrains IntelliJ Idea and install the PHP and Vagrant Plugins. You can search for them under “Settings -> Plugins”.

After they’re installed, restart the IDE and go to “Settings -> Languages & Frameworks -> PHP -> Servers” and create a new server.

For the “host” add “”

Next, click “Use path mappings” and for “File/Directory” set it to the root directory for your code base (on your host OS).

For “Absolute path on the server”, set it to the shared Vagrant directory “/vagrant_data”.

Now click “Apply”.

Now go to “Settings -> Languages & Frameworks -> PHP” and click the “…” and create a new “Remote Interpreter”.

In the Vagrant plugin tab, enter the SSH credentials for the user “vagrant” we created in our VM, and under “PHP executable”, click the “Reload/Refresh” button.

This should search for the remote PHP interpreter running inside the VM and load it. After it is found click “Apply” to save and exit.

Next, we need to configure XDebug in the IDE. Go to “Settings -> Languages & Frameworks -> Debug” and make sure “Can accept external connections” is checked, and change the “Debug port” to “9009” (which is what we set Xdebug to inside the VM).

Click “Apply” to save.

That should be it! 😀

Now go to

If everything is correct, you should be running your code through the VM’s PHP interpreter and XDebug should be communicating back to your IDE from the VM on port 9009. 😀

Now all thats left to do is to test our NFS performance in the VM with http requests using wrk.

Benchmark NFS Performance

dlaroche@laptop-dev:~/workspace/test$ vagrant ssh

// run a 60 second test
vagrant@trusty:~$ wrk -d60s

Output – Vagrant NFS with VMware Provider:

Running 1m test @
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
  Latency    11.31ms   17.66ms 569.96ms   91.76%
  Req/Sec    650.24    245.14     1.01k    75.72%
77209 requests in 1.00m, 0.97GB read
Requests/sec:  1286.56
Transfer/sec:  16.49MB

Output – Native Ubuntu:

Running 1m test @
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
  Latency    11.20ms   21.44ms 426.39ms   92.76%
  Req/Sec   786.50    374.96    2.00k    60.73%

93149 requests in 1.00m, 1.44GB read
Requests/sec:   1550.07
Transfer/sec:   24.60MB

And that’s it! Everything should be working..

If you run into any problems, either comment below, or ping me at

Happy coding! 😀

Creating a Vagrant Base Box with CentOS 6.5, Puppet and Virtual Box

Vagrant is a great tool for developers to use their favorite IDE, within their favorite OS, all while using their favorite VM.
Doing so lets you work in a development environment that is identical to where your application will be deployed.

Puppet is a popular provisioning tool used to duplicate the configuration of systems quickly. Automated system administration. 😀
This article will show how to create a Vagrant Base box with CentOS 6.5 (64-bit), install Puppet Agent and configure it to sync up to your Puppet Master.

Now if you’re thinking… Why would we want to do this when there are tons of base boxes already available?
There are and that’s true, however creating your own allows you to customize what you truly need and don’t need for your team, and also be certain on what’s really installed.

Note: This article assumes you’ve already installed CentOS 6.5 as a Virtual Box VM, the correct Guest Additions for your Virtual Box version, and are already running a Puppet Master.

This article will show you:

  • How to create a Vagrant CentOS 6.5 base box from an already installed CentOS 6.5 VM Image.
  • How to add your newly created base box to Vagrant in order to use it.
  • How to initially provision Vagrant to connect to your company’s Puppet Master.

First we need to install the right version of Vagrant for your OS distro.

Next, we need to boot up your already installed CentOS Virtual Box Virtual Machine.

Next, we’re going to install Puppet Agent on our freshly installed CentOS VM. Our goal (when we do our initial Vagrant provision) is to have Puppet Agent already installed on our base box. This way, we can use Puppet Agent to create our Vagrant environment according to what our dev team’s configuration “node(s) profile” on the Puppet Master is. Puppet Agent will sync up with our Puppet Master to tell us which packages and configurations are needed to install for the Vagrant environment.

Note: Configuring Puppet Master is beyond the scope of this article, but there are many tutorials out there to help.

OK, with our VM in Virtual Box running, login and install Puppet Agent.

Install Puppet Agent

# sudo yum install puppet

Next, we want to be able to use Puppet’s “file_line” function. We’re doing this in order to modify Puppet Agent’s config file with our Puppet Master server location.
We could of manually edited it on the VM before creating our Base Box, but this way gives much more flexibility. You could have more than one team, with each using different Puppet Masters that have different development configurations.

Note: Puppet’s “file_line” function is usually only used for minor file modifications. If you have config files that need to be modified according to a much more complex use case, then the tool you want to use is Augeas.

Install Puppet’s Stdlib module on the VM

# puppet module install puppetlabs-stdlib

Now that those are installed, make sure your VM has everything installed that you initially want (puppet agent, initial packages, hostname, specific dev user/group/permissions, etc), then it’s time to create a Vagrant Base Box from our VM. Don’t worry if you’ve forgot something, you can always go back to the original VM and modify it. Meaning, this won’t modify your VM, it just creates a copy.

Now shutdown your VM. On your host OS we’re going to create the base box.

Create a Vagrant Base Box from your CentOS Virtual Box VM

// --output: the name your base box will be
// --base: your CentOS VM name
# vagrant package --output --base CentOS-6.5-x86_64

This creates a Vagrant base box file in Vagrant’s box directory named

Next we need to add this base box to Vagrant so we can use it.

Add the Base Box to Vagrant

# vagrant box add CentOS-6.5-x86_64_puppet

We can view our base boxes by asking Vagrant.

List the current base boxes

# vagrant box list


Note: I’m storing my base boxes in a custom directory I created just for them that’s off of my SSD drive (since many base boxes can potentially take up a lot of room). Initially Vagrant stores them on the main drive. This can be changed by modifying the default path in your env variables.

Now it’s time to actually *use* Vagrant. 🙂

Create a project directory called “testvagrant” on your host machine and cd to it.

Create and cd to the “testvagrant” directory

# mkdir testvagrant
# cd testvagrant

Next, we’re going to initialize a vagrant environment.

Create Vagrant Env

# vagrant init

This will create a Vagrantfile in the “testvagrant” directory. We’re going to edit this file to setup Vagrant and do our provisioning with Puppet.

Inside our “testvagrant” directory we’re going to create Puppet’s standardized directory tree structure.

Note: This isn’t necessary, it’s just good habit. 🙂

Create the directories

-- puppet
 -- manifests
  -- site.pp
 -- modules
  -- init
   -- manifests
    -- init.pp

Now we want to edit init.pp and add

Add to init.pp

class init {
    # config Puppet Agent (preinstalled on BaseBox)
    # Chaining Arrows (ordering) to prevent race conditions
    file { '/etc/puppet/puppet.conf':
        ensure => 'present',
    } ->
    # server is the location of the Puppet Master domain
    file_line { 'Configure Agent - puppetmaster server':
        path   => '/etc/puppet/puppet.conf',
        ensure => 'present',
        line   => '    server = puppet.ltdev',        
    } ->
    file_line { 'Configure Agent - report':
        path   => '/etc/puppet/puppet.conf',
        ensure => 'present',
        line   => '    report = true',        
    } ->
    file_line { 'Configure Agent - plugin sync':
        path   => '/etc/puppet/puppet.conf',
        ensure => 'present',
        line   => '    pluginsync = true',        

Note: Rememeber, if you have a config use case that’s complicated, use Augeas.

Now we want to edit site.pp and add

Add to site.pp

node default {
    include init

Now that our Puppet Agent config files are ready to be modified we need to setup Vagrant and tell it how to provision. We do this by editing our Vagrantfile.

Edit Vagrantfile configuration

# This is the name of your base box = "CentOS-6.5-x86_64_puppet"

# Our VM will be running our web server on port 80 but forwarding to our host OS on port 8080 "forwarded_port", guest: 80, host: 8080

# This is the directory that will be in sync on your host with your guest (VM) default is 
# /vagrant which is the root directory for that vagrant init (where your Vagrantfile is located)
# Note: I am using Samba for performance reasons with Symfony 2, however try the default 
# sync first.
config.vm.synced_folder ".", "/vagrant", type: "smb"

# Provision with Puppet
config.vm.provision "puppet" do |puppet|
    puppet.manifests_path = "puppet/manifests"
    puppet.manifest_file  = "site.pp"
    puppet.module_path = "puppet/modules"

Now its time to fire Vagrant up and provision! *cough* If everything went correctly.. 🙂

Start Vagrant

# cd testvagrant
# vagrant up


And this is the modification Puppet did by using “file_line” to our /etc/puppet/puppet.conf


Note: Vagrant only provisions on the first “vagrant up”, however you can force it to provision again if you need to by

Force Vagrant Provision

# vagrant up --provision

That’s it. If you need to you can reference how to use Vagrant here.
Have fun! 😀