SJ cartoon avatar

Development Installing WordPress on Vagrant

This is my first post in what feels like a verrry long time, so I’m going to keep it short (or maybe not) and sweet and get back into the groove. Also, there are no clever puns or wordplays here, it’s exactly like the title says, I’m going to write about installing Wordpress on Vagrant.

I’ve written a couple of posts in the past about installing Wordpress locally (here and here), and in those, I briefly extolled the virtues of doing local development

  • in WAMP at the time. However, the fact that I needed to write two articles on doing something as simple as installing WAMP, pulling my site down, and then handling errors that will crop up - well, that really is depressing.

Enter Vagrant

I started using Vagrant about a year or two ago, and only just got around to using it for Wordpress development and testing. The only reason I waited so long is because it’s been a long time since I’ve had enough free time to work on my own side projects. To briefly explain what Vagrant is, it’s effectively a wrapper around virtualization technology (VirtualBox, VMWare, AWS, etc…) and configuration management tools (Ansible, Chef, Puppet, etc…).

My typical use case of it is as a lightweight, headless, Linux virtual machine running on Windows. I’ll spin one up, SSH into it, and do whatever Linux-specific work that needs doing (most commonly, I use it to test how well my cross-platform C++ code compiles using GCC tools).

More recently, it’s been a way for me to write and test web server code outside of a production environment, and without dealing with those annoying network latencies associated with a cloud development environment. In a couple of minutes, I can spin up a VM with a matching configuration to what my production environment is, regardless of how simple or complex. This can range from a simple one file Flask app, to a multi-server, high-availability Couchbase installation (with associated application servers, Sync Gateways, and load balancers)…

Installing Vagrant

First thing’s first. Install Vagrant and whatever virtualization software you would like to use (personally, I’ve been using Virtualbox alongside Vagrant).

  • Download and install Virtualbox and Guest Additions here

  • Download and install Vagrant here

I’m not going to go into all the configuration, settings, and commands associated with either Vagrant or Virtualbox. The getting started page for Vagrant would be a good start, documentation-wise.

Installing Wordpress on Vagrant - From Scratch

If you’ve never taken a fresh Linux distro and installed the requirements necessary for installing Wordpress, I would recommend trying it out manually, to get a feel for the process. Digital Ocean has an excellent tutorial/blog series, and their ones for installing WP are no exception.

I’ve written a Vagrant shell provisioning script (i.e. Bash script) which will automate most of the steps required to go from a fresh Ubuntu installation, to a fully operating Wordpress site.

NOTE: As this is a local installation, I haven’t taken the full set of precautions in terms of hardening Wordpress. So, if you plan to use this script to provision a live, internet facing site, please read through the previous link and also through these two links on the basics of how to harden Linux (here and here). There is some basic security in my scripts, but I will, at some point, write a more detailed article (and thus, automated scripts) on hardening Linux and Wordpress.

Below is only the primary setup script which will be run by Vagrant on provisioning (e.g. when you do ‘vagrant up’ or ‘vagrant provision’). My BitBucket GitHub repo here has the full collection of files needed for the setup script to work. I hope it’s obvious, but the first seven variables should be changed to match your desired setup.

#!/bin/bash

# This is where the variables for the rest of the installation are created
USER=vagrant
DBROOTPASSWORD=qwerty
DBNAME=wordpress
DBUSER=wordpressuser
DBPASSWORD=password
DBPREFIX=wnotp_
SITENAME=sureshjoshi.com

echo "*******************************"
echo "Provisioning virtual machine..."
echo "*******************************"


echo "***********************"
echo "Updating apt sources..."
echo "***********************"
sudo apt-get update -qq > /dev/null


echo "********************************"
echo "Installing and securing MariaDB..."
echo "********************************"

echo "mysql-server mysql-server/root_password password $DBROOTPASSWORD" | debconf-set-selections
echo "mysql-server mysql-server/root_password_again password $DBROOTPASSWORD" | debconf-set-selections
sudo apt-get install -qq mariadb-server > /dev/null
sudo mysql_install_db
# Emulate results of mysql_secure_installation, without using 'expect' to handle input
mysql --user=root --password=$DBROOTPASSWORD -e "UPDATE mysql.user SET Password=PASSWORD('$DBROOTPASSWORD') WHERE User='root'"
mysql --user=root --password=$DBROOTPASSWORD -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"
mysql --user=root --password=$DBROOTPASSWORD -e "DELETE FROM mysql.user WHERE User=''"
mysql --user=root --password=$DBROOTPASSWORD -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'"
mysql --user=root --password=$DBROOTPASSWORD -e "FLUSH PRIVILEGES"


echo "********************************************************"
echo "Installing PHP and disabling path info default settings..."
echo "********************************************************"
sudo apt-get install -qq php5-fpm php5-mysql php5-gd libssh2-php > /dev/null
sudo cp /etc/php5/fpm/php.ini /etc/php5/fpm/php.ini.orig
sudo sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/' /etc/php5/fpm/php.ini
sudo service php5-fpm restart


echo "***********************************************"
echo "Installing NGinx and removing default config..."
echo "***********************************************"
sudo apt-get install -qq nginx > /dev/null

# If you want to test your Nginx-PHP config, uncomment the lines below, but be SURE to delete the .php file after testing
# sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.orig
# sudo cp /vagrant/provision/nginx.php /etc/nginx/sites-available/default
# sudo service nginx reload
# sudo cp /vagrant/provision/info.php /usr/share/nginx/html/info.php

# Remove the default nginx config from sites-enabled
sudo rm /etc/nginx/sites-enabled/default


echo "*********************************"
echo "Setting up NGinx for Wordpress..."
echo "*********************************"
sudo cp /vagrant/provision/nginx/common /etc/nginx -r
sudo cp /vagrant/provision/nginx/wptemplate.nginx /etc/nginx/sites-available/$SITENAME
sed -i "s/SITENAME/$SITENAME/g" /etc/nginx/sites-available/$SITENAME
sudo ln -s /etc/nginx/sites-available/$SITENAME /etc/nginx/sites-enabled/
sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
sudo cp /vagrant/provision/nginx/nginx.conf /etc/nginx/
sudo service nginx reload
sudo service php5-fpm restart


echo "************************************"
echo "Setting up database for Wordpress..."
echo "************************************"
mysql --user=root --password=$DBROOTPASSWORD -e "CREATE DATABASE $DBNAME;"
mysql --user=root --password=$DBROOTPASSWORD -e "CREATE USER $DBUSER@localhost IDENTIFIED BY '$DBPASSWORD';"
mysql --user=root --password=$DBROOTPASSWORD -e "GRANT ALL PRIVILEGES ON $DBNAME.* TO $DBUSER@localhost;"
mysql --user=root --password=$DBROOTPASSWORD -e "FLUSH PRIVILEGES;"


echo "********************************************************"
echo "Downloading and installing Wordpress and dependencies..."
echo "********************************************************"
# Download and extract Wordpress, and delete archive
wget https://wordpress.org/latest.tar.gz -q -P /tmp
tar xzfC /tmp/latest.tar.gz /tmp
rm /tmp/latest.tar.gz


echo "***********************************************************"
echo "Setting up Wordpress configurations and file permissions..."
echo "***********************************************************"
# Setup Wordpress config file with database info
cp /tmp/wordpress/wp-config-sample.php  /tmp/wordpress/wp-config.php
sed -i "s/database_name_here/$DBNAME/"  /tmp/wordpress/wp-config.php
sed -i "s/username_here/$DBUSER/"       /tmp/wordpress/wp-config.php
sed -i "s/password_here/$DBPASSWORD/"   /tmp/wordpress/wp-config.php
sed -i "s/wp_/$DBPREFIX/"               /tmp/wordpress/wp-config.php

# Add authentication salts from the Wordpress API
SALT=$(curl -L https://api.wordpress.org/secret-key/1.1/salt/)
STRING='put your unique phrase here'
printf '%s\n' "g/$STRING/d" a "$SALT" . w | ed -s /tmp/wordpress/wp-config.php

# Move Wordpress to appropriate directory and set file permissions
SITEPATH=/var/www/$SITENAME
sudo mkdir -p $SITEPATH/html
sudo rsync -aqP /tmp/wordpress/ $SITEPATH/html
sudo mkdir $SITEPATH/html/wp-content/uploads
sudo chown -R $USER:www-data $SITEPATH/*
rm -r /tmp/wordpress

# Setup file and directory permissions on Wordpress
sudo find $SITEPATH/html -type d -exec chmod 0755 {} \;
sudo find $SITEPATH/html -type f -exec chmod 0644 {} \;
sudo chmod 0640 $SITEPATH/html/wp-config.php


echo "**************************************************************"
echo "Success! Navigate to your website's URL to finish the setup..."
echo "**************************************************************"

Installing Wordpress on Vagrant - Using Duplicator

Unlike in the previous section, this section assumes you have already built a Wordpress site, installed plugins, themes, have posts and comments, and would like to move that whole site to Vagrant for development purposes.

In my post about installing Wordpress on WAMP, I did a lot of the grunt work myself and copied files, pulled down the database manually, and a few other things. Since then, I have discovered the awesomeness of the free Duplicator plugin by LifeInTheGrid. This plugin makes it incredibly easy to backup your current site, and re-install it elsewhere (almost scarily easy actually).

I’ve, thus, created a secondary provisioning script that prepares my VM with the necessary environment to run Duplicator and Wordpress (it’s a very similar script, except there are fewer steps).

NOTE: To run Duplicator, it’s necessary to give a slightly higher level of permission to the root directory of your install. I would recommend going back in and locking this down after Duplicator finishes.

Again, below is only the primary setup script which will be run by Vagrant on provisioning (e.g. when you do ‘vagrant up’ or ‘vagrant provision’). My BitBucket GitHub repo here has the full collection of files needed for the Duplicator setup script to work (make sure to copy your installer.php, and backup file into the ‘duplicator’ directory).

#!/bin/bash

# This is where the variables for the rest of the installation are created
USER=vagrant
DBROOTPASSWORD=qwerty
DBNAME=wordpress
DBUSER=wordpressuser
DBPASSWORD=password
DBPREFIX=wnotp_
SITENAME=sureshjoshi.com

echo "*******************************"
echo "Provisioning virtual machine..."
echo "*******************************"


echo "***********************"
echo "Updating apt sources..."
echo "***********************"
sudo apt-get update -qq > /dev/null


echo "********************************"
echo "Installing and securing MariaDB..."
echo "********************************"

echo "mysql-server mysql-server/root_password password $DBROOTPASSWORD" | debconf-set-selections
echo "mysql-server mysql-server/root_password_again password $DBROOTPASSWORD" | debconf-set-selections
sudo apt-get install -qq mariadb-server > /dev/null
sudo mysql_install_db
# Emulate results of mysql_secure_installation, without using 'expect' to handle input
mysql --user=root --password=$DBROOTPASSWORD -e "UPDATE mysql.user SET Password=PASSWORD('$DBROOTPASSWORD') WHERE User='root'"
mysql --user=root --password=$DBROOTPASSWORD -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"
mysql --user=root --password=$DBROOTPASSWORD -e "DELETE FROM mysql.user WHERE User=''"
mysql --user=root --password=$DBROOTPASSWORD -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'"
mysql --user=root --password=$DBROOTPASSWORD -e "FLUSH PRIVILEGES"


echo "********************************************************"
echo "Installing PHP and disabling path info default settings..."
echo "********************************************************"
sudo apt-get install -qq php5-fpm php5-mysql php5-gd libssh2-php > /dev/null
sudo cp /etc/php5/fpm/php.ini /etc/php5/fpm/php.ini.orig
sudo sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/' /etc/php5/fpm/php.ini
sudo service php5-fpm restart


echo "***********************************************"
echo "Installing NGinx and removing default config..."
echo "***********************************************"
sudo apt-get install -qq nginx > /dev/null

# If you want to test your Nginx-PHP config, uncomment the lines below, but be SURE to delete the .php file after testing
# sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.orig
# sudo cp /vagrant/provision/nginx.php /etc/nginx/sites-available/default
# sudo service nginx reload
# sudo cp /vagrant/provision/info.php /usr/share/nginx/html/info.php

# Remove the default nginx config from sites-enabled
sudo rm /etc/nginx/sites-enabled/default


echo "*********************************"
echo "Setting up NGinx for Wordpress..."
echo "*********************************"
sudo cp /vagrant/provision/nginx/common /etc/nginx -r
sudo cp /vagrant/provision/nginx/wptemplate.nginx /etc/nginx/sites-available/$SITENAME
sed -i "s/SITENAME/$SITENAME/g" /etc/nginx/sites-available/$SITENAME
sudo ln -s /etc/nginx/sites-available/$SITENAME /etc/nginx/sites-enabled/
sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
sudo cp /vagrant/provision/nginx/nginx.conf /etc/nginx/
sudo service nginx reload
sudo service php5-fpm restart


echo "************************************"
echo "Setting up database for Wordpress..."
echo "************************************"
mysql --user=root --password=$DBROOTPASSWORD -e "CREATE DATABASE $DBNAME;"
mysql --user=root --password=$DBROOTPASSWORD -e "CREATE USER $DBUSER@localhost IDENTIFIED BY '$DBPASSWORD';"
mysql --user=root --password=$DBROOTPASSWORD -e "GRANT ALL PRIVILEGES ON $DBNAME.* TO $DBUSER@localhost;"
mysql --user=root --password=$DBROOTPASSWORD -e "FLUSH PRIVILEGES;"


echo "********************************"
echo "Transferring Duplicator files..."
echo "********************************"
SITEPATH=/var/www/$SITENAME
sudo mkdir -p $SITEPATH/html
sudo cp /vagrant/provision/duplicator/* $SITEPATH/html/
sudo chown -R $USER:www-data $SITEPATH/*

# Setup file and directory for Duplicator - CHANGE 0775 back to 0755 after Duplicator is finished
sudo find $SITEPATH/html -type d -exec chmod 0775 {} \;
sudo find $SITEPATH/html -type f -exec chmod 0644 {} \;


echo "**************************************************************"
echo "Success! Navigate to your website's URL to finish the setup..."
echo "**************************************************************"

And finally

I would be remiss not to mention some of the existing solutions to what I just did by hand.

EasyEngine by rtCamp is essentially a collection of Bash scripts which manage a Wordpress installation. You tell it what kind of installation you want, whether you want caching plugins, or to use multisite, and it will then run a series of scripts to setup that installation for you (including configurations for Nginx and PHP). I think it’s pretty cool, and you can use it inside of Vagrant to test it out, but personally, everything I just wrote about, I did by hand to learn a bit more about web server infrastructure.

And another finally

My Bitbucket repo GitHub repo (https://github.com/sureshjoshi/vagrant-examples) will have any updates I make to these files, so I recommend checking it out!