Switching back to a local develop environment

My thoughts and process of setting up a local LAMP stack for an improved development workflow.

Posted by Eddo on July 13, 2017

In order to improve the development workflow in our team, with regard to our development environment, I started to look into a number of options. The reason being is that I’m fed up 😡 with my develop environment being out of sync due to PhpStorm not uploading files to our development server upon executing a VCS (Version Control System) update. At times our database backup restore process also hinders our development process, costing us precious time.

Various options that I considered:

  • Find an IDE that does work correctly, i.e. uploading files to the develop server when doing a VCS update
  • Creating a script that runs locally to rsync files the develop server, and trigger that either upon a VCS update or manually
  • Work from a local develop environment using modern tooling

After some research I decided actually that it would be a nice challenge and opportunity to gain experience with more modern tooling, such as Vagrant, Ansible, Chef, and maybe Docker. The first time I heard about Vagrant was in a talk by Thijs Feryn at local developers meetup in Deventer (NL), organized by Drukwerkdeal.nl. It almost felt like I was the only one who hadn’t learned about this application/tool at the time 😳, yet I fortunately wasn’t. Vagrant is a relatively simple way to run portable virtual machines (VMs) on your local development workstation. Its strong points are that you can recreate a production environment locally, and hand over the configuration to a colleague or automated machine, and then will get the exact same environment, without having to handover a huge image file of the VM. The Vagrant configuration file can be stored together with your application code in the version control system of your liking.

With just a Vagrant VM you are not yet there, unless you want to configure your VM every now and then completely manually. You can use provisioning scripts to setup your VM with the right applications and tools that are not installed by default in the used box. You can use Vagrant’s own provisioning scripts, yet for more elaborate environments you could use a provisioning tool like Ansible, Chef or Puppet.

Chef and Puppet rely on another server to serve the cookbooks and a client that actually provisions the VMs. As for a local development server that is a bit overkill IMHO, although Chef is also allowing to run locally, I decided it was more suitable to continue with Ansible for local development environments. For provisioning production or test environments both Chef and Puppet probably have the advantage here.

Unfortunately, I discovered initially that you need a Linux or Mac host controller for Ansible, and we do work on Windows laptop; yet there are workarounds: Using cygwin, like Torben Knerr mentions using it inside the VM itself, or using a separate “control” VM. A better solution I found was actually installing Ansible on your Vagrant VM, and ensure to execute the provisioning inside that VM itself via the Vagrantfile “Using Ansible with Vagrant and Windows”, by Scott Keck-Warren and using “ansible_local”.

Through the vagrant-guest_ansible provisioner you could even make this more beautiful and host-platform independent, which would be an advantage should we in the future switch host OS.

My experiences so far

What are the requirements used for our team and product:

  • Currently running on CentOS
  • Application is written in PHP, with a MySQL database
  • Multitenancy software architecture; one codebase, shared by multiple customers yet each using their own database and URLs
  • Microsoft Windows laptops used as development workstations (although I would like to see that change)

We’re about to migrate everything to PHP 7.1, yet do require to test our written code on an older PHP version; two VMs on one host may make this project a bit more approachable, or continue to run a local develop environment and the test environment on an actual server.

Right now I’m using a derivative of this bootstrap script to provision the server. At first I thought they were tough to write from scratch, yet the Ansible configuration were even more complicated, and this bootstrap script made me simplify the server setup. I made some changes to use php7 instead of php5.5. I’ve been destroying and building the server for a few times now, and it seems to hold up, although I discovered some tweaks after running our application that are now also added to the bootstrap.sh script, as our application apparently doesn’t work right now with sql_mode = "full_group_by".

Side note: The one thing I found weird is that within the Windows shell (cmd.exe) I couldn’t get vagrant ssh to work, yet when using an application like MobaXterm or putty I could get it to work with the private key for the VM… for now it works, so I might pick it up later.


Evolutionary design recognizes that people learn by trying things out. In programming terms developers experiment with how to implement a certain feature and may make a few attempts before settling down to a preferred alternative. Database design can be like that too. As a result it’s important for each developer to have their own sandbox where they can experiment, and not have their changes affect anyone else.

Source: Unnecessary evil of shared development

Through using a local development environment every developer in our team has their own sandbox environment to play around with, yet as we’re working with a copy of some production data, we’d like to have a simple structure to refresh our local environment in order to reproduce customer issues with their data. The question arises whether we actually need customer data to be restored on our local develop environments.

For now the approach I’ve taken is to update the database on our local develop environment manually, by unzipping the backups and piping that directly into the corresponding database if needed. This is a small step backwards from the current approach on our own dev-server, where that process including anonimizing the data is automated, yet that will be picked up again.

The real test will come when other team members will start using this workflow, yet at the moment it isn’t that ready yet (I know, I’m a bit of a perfectionist 😔).

Some next steps

Setting up your local development environment, in an automated fashion, will make it easier in the future to setup a production server from scratch

Improved deployment of our production servers whenever we need a new one. At the moment we have a strategy of cloning another production server to setup a new one, yet with the strategy of applying automated configuration and instantiation (via the likes of Puppet or Chef) we can get to a next level, and reduce risks in not having software up-to-date or running unnecessary software on our servers.

The one thing that I’m still missing in this approach is being able to debug PHP code while it is running, yet I have already found one article that can help in running XDebug, PhpStorm and Vagrant. For me it is a vital part of the development process to debug code.

And above all else, actually include the use of the local develop environment in our development workflow 🙌.

Credit for header image Émile Perron

P.S. If you’ve enjoyed this article or found it helpful, please share it, or check out my other articles. I’m on Instagram and Twitter too if you’d like to follow along on my adventures and other writings, or comment on the article.