Over the past few months, I’ve been meaning to create a staging WordPress blog that is an exact replica of my production OMNINOGGIN blog so I can test major feature changes before releasing them to my production site. I have to admit that there are many other interesting things to spend time on (see also: Make Popularity Contest Work with WP-Super-Cache and NowThen Photo Display WordPress Plugin) so I have been lagging at getting this task done. Fortunately the WordPress 2.5 released was enough to motivate me to get this done. My goal in this post is to provide a step-by-step set of instructions (or checklist) for getting this task done. I run Apache 2.2.8, MySQL 5.0.51a, and PHP 5.2.5 on a FreeBSD 7.0 machine that I have complete control over. Keep in mind that these steps will vary depending on how your blog is configured. It is a good checklist nonetheless so without further ado:
- Create a new virtual host in your web server’s configuration file. Call it something like staging.your-domain.com. Using apache as an example, you can add the following lines into your /usr/local/etc/apache22/httpd.conf:
<VirtualHost *:80> ServerAdmin webmaster@YOUR-DOMAIN.com DocumentRoot /usr/local/www/apache22/data/YOUR-WEBROOT_staging ServerName staging.YOUR-DOMAIN.com ErrorLog /var/log/httpd-error-YOUR-DOMAIN_staging.log CustomLog /var/log/httpd-access-YOUR-DOMAIN_staging.log combined </VirtualHost>
Then gracefully restart your apache by running:
/usr/local/etc/rc.d/apache22 reload
- If you are hosted with a provider that has users a dynamic IP address, add this new staging.your-domain.com to your DNS update software. For ddclient (and ZoneEdit service) add the following to your /usr/local/etc/ddclient.conf:
server=www.zoneedit.com,\ protocol=zoneedit1,\ login=YOUR-ZONEEDIT-USERNAME,\ password=YOUR-ZONEEDIT-PASSWORD\ YOUR-DOMAIN.com,www.YOUR-DOMAIN.com,staging.YOUR-DOMAIN.com
Note that the commas and backslashes have to be exactly placed as shown on the first 4 lines.
- Duplicate the WordPress database by running the following commands:
On command line:mysql -u YOUR-MYSQL-USERNAME -pYOUR-MYSQL-PASSWORD
Notice that there is no space between the -p flag and your password.
In MySQL:create database YOUR-WORDPRESS-DB_staging; grant all on YOUR-WORDPRESS-DB_staging.* to 'your-mysql-username'@'localhost'; grant all on YOUR-WORDPRESS-DB_staging.* to 'your-mysql-username'@'%'; quit;
On command line:
mysqldump --opt YOUR-WORDPRESS-DB -u YOUR-MYSQL-USERNAME -pYOUR-MYSQL-PASSWORD | mysql -D YOUR-WORDPRESS-DB_staging -u YOUR-MYSQL-USERNAME -pYOUR-MYSQL-PASSWORD
The –opt flag will take care of all the necessary table locking/unlocking in addition to a number of other great things for you.
- Change the “siteurl” and “home” options in the newly copied database. If this is not done, your staging site will always redirect you to your production site.
On comand line:mysql -u YOUR-MYSQL-USERNAME -pYOUR-MYSQL-PASSWORD
In MySQL:
update wp_options set option_value='http://staging.YOUR-DOMAIN.com' where option_name in ('siteurl', 'home');
- Set your privacy to private so your staging site is not visible to the world.
In MySQL:UPDATE wp_options SET option_value=0 WHERE option_name = 'blog_public'; quit;
- Duplicate the WordPress code by running the following commands:
rsync -aP --delete --exclude="DIR1" --exclude="DIR2" YOUR-WEBROOT YOUR-WEBROOT_staging
This will perform a one way synchronization from production files to staging files with the exception of “DIR1″ and “DIR2″ directories (use this as needed). Extraneous files are deleted on the staging side.
- Create a .htpasswd file by running the following command:
htpasswd -bcm .htpasswd YOUR-USERNAME YOUR-PASSWORDMove this file to a safe place (not in your WEBROOT_staging directory). We will be using this in the next step.
- Create a .htaccess file under YOUR-WEBROOT_staging and add the following into it to password protect your staging site.
AuthName "Section Name" AuthType Basic AuthUserFile FULL-PATH-TO-YOUR-.htpasswd-FILE Require valid-user
Make a copy of this file and put it in a safe place (not in your WEBROOT_staging directory) as we may reuse this in the future.
- Change the database used in WEBROOT_staging/wp-config.php by replacing:
define('DB_NAME', 'YOUR-DATABASE-NAME');
with
define('DB_NAME', 'YOUR-DATABASE-NAME_staging');
- Make sure you disconnect your staging site from the rest of the world. Disable all plugins that generate sitemaps as these tend to report site changes to the search engine too. Disable all statistics plugins/javascripts that share the same counter database as your production site (A good example of this is Google Analytics & chCounter). You might have more of these kind of plugins in your blog so do another review of your plugins and theme.
- Unless you want to test caching, I would disable plugins like WP-Super-Cache and WP-Cache also (makes development a lot easier).
- I like to change the color of the Blog background and Admin background to something ridiculous so I can easily tell the difference between the staging and product site. You may modify the background of the admin interface by editing /wp-admin/css/colors-fresh (or colors-classic, depending on which one you are using).
Phew! I didn’t think it would be this extensive when I first imagined making a staging WordPress site. The good news is that once you’ve done it, you can skip many steps if you are planning to do a production -> staging clone. All you have to do is convert steps 3-6 into a script, and also have it copy your previously saved .htaccess file into your WEBROOT_staging after the rsync. You can include steps 9-12 into the automation script with a bit of ingenuity. I will post my script to do this synchronization once I write one up.
Update:
Here is the script I use to automatically clone my production blog to a staging blog. After running the script, all I do is go into wp-admin and disable all the “linking to the outside world” plugins. Hope this helps!
Download clone.zip
Have I covered all the basis? Do you have a better way at doing this? Please share your ideas in the comment form below.