WordPress Development with Vagrant

August 12, 2013 Mark Malek

I’ve always dreaded working with WordPress. I’m not one who likes to modify code in a production environment and hope for the best. I like to have a local development environment where I can freely code and test new features and make template changes without breaking anything in production.

One of the reasons why I dread working with WordPress is the process involved to copy an existing site to another environment and have all the same content. If you’ve spent countless hours creating your page content, posts, and other dynamically generated data for your new site, you probably would also like to have the same content in your development environments. Especially if you like to work and design around your real content and not with generated Lorem Ipsum text.

This is where Vagrant comes in to save the day. Using Vagrant has many advantages. You don’t have to ftp your files anywhere every time you make a change, just make your code changes, save, and refresh the browser. If you’re working with a team, you don’t all have to go through the process of configuring apache, php5, mysql on each of your machines. Setup Vagrant once, check it into your source repository and everyone has a working local development environment for WordPress with all the same data.

There are many ways to export data from an existing WordPress site and get it setup in a new environment.

  • Use the plugin BackupBuddy.
  • Use WordPress’ export feature to export all the content as an XML file.
  • Back up your database with mysqldump.

Once you have a backup of your data, you will need to setup your local machine with Apache (or your web server of choice), PHP, and MySQL. You will also need to create a database, setup your database user, and setup a new installation of WordPress with your custom theme. If you use BackupBuddy, it will setup a new WordPress installation with your theme and database configurations for you. Fairly painless with BackupBuddy, but still requires some work. Each time you setup a new environment you have to repeat all the steps above. Who really wants to go through the WordPress setup process every time?

I wanted to do all of the above but with a single command.

vagrant up

Vagrant allows me to run a virtual development environment that mirrors the production environment. Vagrant is also platform agnostic. If another developer using a different OS needs to work on the WordPress site he can also get up and running using the same command. He doesn’t need to spend time setting up PHP, MySQL, or a web server on Windows or his OS of choice.

Before I get into the details in setting up vagrant for the first time, you will need a few things:

  • Download and install Vagrant for your OS from Vagrant
  • Download VirtualBox for your OS from VirtualBox (VirtualBox is a free virtualization product, you could also use VMware or other providers)
  • Back up your production WordPress database using mysqldump.

When you’ve downloaded the required software, its simple to install, just double click the installers and click next a few times. Once you’ve completed the process you’ll need to initialize a new Vagrant project in your WordPress repository. From the command line:  

$ cd /path/to/project $ vagrant init

This will create a Vagrantfile in your current directory. The Vagrantfile is your configuration for Vagrant. If you opened the Vagrantfile you would see it contains a lot of examples and comments.

Next step is to add a Box, which is a base image for your virtual environment. Building a virtual machine from scratch is a slow time consuming process. Ain’t nobody got time for that! You can read more about Boxes. To add a box from the command line run:

vagrant box add {box name} {HTTP source for the box}

as an example using VirtualBox *note: boxes are provider specific:

vagrant box add precise64 http://files.vagrantup.com/precise64.box

Now that we’ve added a box that can be used as our base image (base images are never modified by Vagrant so that they can safely be re-used across projects) we’ll need to configure the WordPress project to use it. Open the Vagrantfile in your project and change the following line:

config.vm.box = "precise64" # the name of the box you added in the previous step

If you were to enter vagrant up from the command line in your project directory, you’d have a clean virtualized environment up and running. This doesn’t do us much good yet. Next step is to create a shell script that can configure the box with our dependencies.

For simplicity I use a shell script but Vagrant supports provisioning your environment with Chef recipes or Puppet. This is what my shell script looks like. We’ll go over it line by line next. 

Your script may differ depending on what distro you are using.

First step is to install apache2 and php5.

sudo apt-get install -y apache2 php5 libapache2-mod-php5 php5-mcrypt

The next step is to symlink /var/www (This is where Apache will be serving your WordPress site from) to /vagrant. Vagrant by default will sync your project folder on your host machine to /vagrant on your guest machine.

rm -rf /var/www ln -fs /vagrant /var/www

Now we need to install MySQL. The reason we did not include mysql-server with the rest of the packages is because the installation will prompt you to set a root password. We don’t want our provisioning of the guest machine to be interrupted by annoying prompts so we’ll include our root password in our script. I would recommend using a generic password here since this script will be checked into the repository.

The first two lines seen here are used for the MySQL installation prompts: password and repeat password. Then installing mysql-server. 

sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password <your_db_password>' sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password <your_db_password>' sudo apt-get -y install mysql-server

Since we’ll be using the Apache2 mod_rewrite module we will need to enable it.

a2enmod rewrite

We will then need to create our site’s apache configuration with our rewrite rules. 

cat >/etc/apache2/sites-available/<your_site_name>.conf <<EOL <VirtualHost *:80>   DocumentRoot /var/www   <Directory /var/www>     Options Indexes FollowSymLinks MultiViews     AllowOverride All     RewriteEngine On     RewriteCond %{REQUEST_FILENAME} !-f     RewriteRule ^ index.php [QSA,L]   </Directory> </VirtualHost> EOL

If you notice, we’re setting our DocumentRoot to /var/www which we earlier symlinked to /vagrant. You could also just set your DocumentRoot to /vagrant and skip the previous symlink step.

We will also want to disable the default apache site configs and enable our newly created config and restart apache to load our new module and configs.

sudo a2dissite default sudo a2ensite <your_site_name>.conf sudo service apache2 restart

Now we get to finally create and seed our database. 

mysql -u root -p<your_database_password> -e "CREATE DATABASE <your_database_name>;" mysql -u root -p<your_database_password> -e "CREATE USER '<your_database_user>'@'localhost' IDENTIFIED BY '<your_database_password>';" mysql -u root -p<your_database_password> -e "GRANT ALL PRIVILEGES ON *.* TO '<your_database_user>'@'localhost';" mysql -u root -p<your_database_password> -e "FLUSH PRIVILEGES;" mysql -u root -p<your_database_password> <your_database_name> < /var/www/vagrant/database_seed.sql

First step is to create the database; database user and password; and grant privileges to the user. If you use your production database name, user, password you will not need to modify your wp-config.php but this is not recommended since this script will be checked into the repository and you don’t want to store credentials with your source code for security reasons. There are a number of ways around this, including using environment variables, but that is out of scope for this blog post.

Once the database is seeded, we need to go through and update WordPress’ base url (or site url) and all our posts and pages with absolute links to use our local hostname. 

mysql -u root -p<your_database_password> -e "UPDATE <your_database_name>.wp_posts SET guid = replace(guid, 'http://www.<url_from_production>.com','http://<your_local_hostname>');" mysql -u root -p<your_database_password> -e "UPDATE <your_database_name>.wp_posts SET post_content = replace(post_content, 'http://www.<url_from_production>.com', 'http://<your_local_hostname>');" mysql -u root -p<your_database_password> -e "UPDATE <your_database_name>.wp_options SET option_value = 'http://<your_local_hostname>' where option_name = 'siteurl';"

Phew, that sounds like a lot! Lucky for us, we never have to go through these steps again. We just need to tell Vagrant to run this script when our guest machine is provisioned. You can do this by adding the following line to your Vagrantfile:

config.vm.provision :shell, :path => "vagrant/bootstrap.sh"

I like to dump all my vagrant provisioning scripts into a single folder in my project directory. This makes it easier for my deploy scripts to exclude or remove them from production.

If you’ve been using WordPress for a while, you already know that at times, it has to write to disk. Downloading new plugins, upgrading WordPress to a new version, or generating .htaccess files for fancy permalinks. In our current state, we lack the permissions for WordPress to be able to write to our /vagrant synced folder without modifying permissions on our host machine. To fix this there is one last change we need to make to our Vagrantfile, taken from this server fault answer.

config.vm.synced_folder ".", "/vagrant", :extra => "dmode=777,fmode=666"

This will allow WordPress to upgrade itself, add or upgrade plugins, and generate .htaccess files if needed.

Now that we’ve configured Vagrant. We can start using it. From the command line in your project directory:

vagrant up

You now have a local development environment running your WordPress site with all your content from production. You can access this site from your host machine’s browser with localhost:8080 which is mapped to port 80 on your guest machine. You can change the ports in your Vagrant file if needed:

config.vm.network :forwarded_port, guest: 80, host: 8080

What I did on my local machine instead of using localhost was setup a virtual host for dev.distilnetworks.com to proxy to This allows me to use dev.distilnetworks.com as my WordPress site url and accessible through my browser on my host machine. If you’re using Apache, to set this up you might use something that looks like 

<VirtualHost *:80>   ServerName dev.distilnetworks.com   ProxyPreserveHost On   ProxyPass /   ProxyPassReverse / </VirtualHost>

There are many ways we could improve the bootstrap script. For instance, if you have scheduled weekly database backups with BackupBuddy in production, you could have your script pull the latest backup to seed your development database when you provision a new guest machine. The nice thing about Vagrant is we don’t always have to keep a guest machine around when we’re not using it. We can free up those resources when we’re done. The next time you need to start working just type vagrant up and you’re development environment is back up and running in minutes.

For more information about Vagrant, check out their getting started guide

About the Author

Mark Malek

Mark Malek has a passion for all things front end. As VP of Engineering at Distil, his responsibilities include the design and development of all customer facing applications such as the Distil Portal. Previously Mark was a front end engineer at 6fusion and iContact.

Follow on Twitter More Content by Mark Malek
Previous Article
What You Need to Know About Web Scraping: How to Understand, Identify, and Sometimes Stop
What You Need to Know About Web Scraping: How to Understand, Identify, and Sometimes Stop

The challenge of web scraping is relevant to every player in the travel industry. Travel suppliers, OTAs an...

Next Article
Travelers Beware – Your Travel Agent May Be a Bot
Travelers Beware – Your Travel Agent May Be a Bot

Bots, crawlers and web scrapers are not working for travelers; bots are not transparent, democratizing agen...