Setting up a PHP development environment with Vagrant

Setting up a development environment is not always easy, specially for web development. Sometimes you need to install and configure plenty of applications. A database server, a web server, server-side programming language binaries, mail server, job queue server, specific package managers, building tools, debug and profiling tools, etc.

Each one of them will need to be in a concrete version, and you will need to handle their dependencies too. You could think that's a one time task, but what happens when you work on multiple projects at the same time. You need to install that for each one of them, and also make sure there are no conflicts with different environments.

There is a tool that eases this task, called Vagrant, that allows us to create a virtualized environments with all the tools, system packages and applications we need to use in a project. Each environment is running on its own virtual machine, so there is no conflicts between them.

The configuration of each virtual machine is defined in a file, that can be pushed to the VCS server, so that any other team member can use the same exact environment as you. By using that file, Vagrant creates a machine, downloads the OS and installs it, installs the packages and starts services, so that we can start working in no time.

This is a much more efficient way to work, since that configuration file (called Vagrantfile) can be reused multiple times.

Installing vagrant

Vagrant is a command line tool which eases the interaction with the virtual machines. Start a machine, halt a machine open a SSH connection or refresh the configuration by reading the Vagrantfile are easy tasks which only need a certain command to be executed.

There are packages for every major operating system that can be downloaded from here.

You will also need to install VirtualBox to handle virtual machines. Others are supported too.

Creating the Vagrantfile

The Vagrantfile is the main configuration file for the virtual machine. It defines the operating system to be used, the system packages to be installed and how to do it, ports to be mapped to the host machine, folders to be shared, etc.

It is usually placed in the root directory of your project, since the folder containing it will be mapped to the folder /vagrant inside the virtual machine. This way the complete project will be available inside the virtual machine, for example to be served by a web server.

A simple example of a Vagrantfile could be this.

Vagrant.configure("2") do |config|

    # This is the operating system to be installed. Ubuntu 12.04 in this case
    config.vm.box = "hashicorp/precise32"

    # The script "bootstrap.sh" will we run within the virtual machine once installed
    config.vm.provision :shell, path: "bootstrap.sh"

    # The port 8888 will be forwarded from the local machine to the virtual machine's port 80
    config.vm.network :forwarded_port, host: 8888, guest: 80

end

This is very easy to undertand. We are telling vagrant to install Ubuntu 12.04, start the machine and run the bootstrap.sh script, which could be used to define which system packages to install.

Then, we forward the port 8888 in the local machine to the port 80 in the virtual machine, so that we can see the application by accessing to http://localhost:8888.

You have an example project using this Vagrantfile here. Clone it, go to the folder and run vagrant up. Once it finishes go to http://localhost:8888 and you should see a nice Hello World! which is being served from the virtual machine.

However, this example is too simple. In real projects we usually have more complex requirements, and configuring the complete Vagrantfile is not so easy.

For this situations, we have multiple online assistants which can be used to create more complex Vagrantfiles. One of the best for PHP projects is PuPHPet, which is based on Puppet.

Setting up the machine

The first step is to go to PuPHPet's webpage and follow the steps of the wizard. Select the operating system to be installed, the web server, the PHP version and such, the result depends on your needs. Once you finish this you will be able to download a complete configuration file.

Extract downloaded file wherever you want, open a console and go to the extracted folder. Now run vagrant up and the machine will be created and configured. This process may take some time, so be patient.

After a while, the virtual machine will be up an running. You can take a look at the extracted Vagrantfile and see that it is a little more complex than the first example.

If you include the Vagrantfile and the puphpet folder in your project's VCS you will be able to reproduce the same environment anywhere you go just by clonning the repository.

Guest and host machine integrations

SSH access: One of the more common things we'll need to do is to open a SSH connection against the virtual machine. To accomplish that task we just need to go to the folder where the Vagrantfile lives, or one of its subfolders and run vagrant ssh. Now you are able to do anything on the virtual machine as if it were your host machine.

Folders sync: Another thing we'll probably need to do is to sync folders between the host machine and the guest machine. As I said earlier, the Vagrantfile parent folder is mapped by default to the /vagrant folder in the virtual machine, but we could change the folders in case of need.

To define a folder that should be synced, just place a line like this in your Vagrantfile.

config.vm.synced_folder "subfolder/", "/anywhere/else/in/the/virtual/machine"

Port forwarding: This was seen in the first example. We could map a port in the host machine to another port in the virtual machine so that requests to the first one are forwarded to the other. We could also access the virtual machine IP or hostname directly, that depends on our needs.

Managing virtual machines

After some time working with vagrant you'll probably have more than one virtual machine created and vagrant also provides some commands to handle them. By the way, the virtual machines in vagrant are called boxes.

We have seen that the vagrant up command creates a virtual machine, but it also turns on a previously halted box. To safely halt a virtual machine, just run vagrant halt and all the resources will be freed. We have also the vagrant suspend which, as you can guess, is used to suspend a box and vagrant resume, which resumes a suspended box.

Sometimes we will need to update a virtual machine. Updating the Vagrantfile and running the vagrant up command is not enugh for already created boxes, you will need to run vagrant reload so that the Vagrantfile is processed again. If you also need to refresh the provisions (the bootstrap.sh script in our first example) either run vagrant provision or vagrant reload --provision which will both reload the configuration and provision the machine.

Finally, when you need to delete a virtual machine, just run vagrant destroy.

You can also manage all the boxes you have installed, without having to be in the directory of a specific machine, by using the commands under vagrant box. Try vagrant box help to see what's available.

Conclusion

This is pretty much it. This will let you encapsulate a PHP project inside a virtual machine, allowing you to use different applications and services on each one of them and "tracking" the state of the machine itself so that any collaborator can work in the same environment as you.

Of course there are other advanced usages for Vagrant, like deployment of machines to virtualization systems like Amazon Web Services, but that's another articles subject.

For a complete vagrant documentation, follow this link.