Cloning a live WordPress site to a local Mac test environment

As you customize WordPress and extend its functionality with various plugins, and the usual barrage of software updates starts arriving, it becomes increasingly useful to have a local environment to try things out.

A local environment allows you to safely test new plugins and themes, new versions of existing plugins and themes, new versions of WordPress, and all sorts of other changes, without affecting the live site. If anything goes wrong, you can always roll the local site back to a known good state.

The steps necessary to create a local WordPress environment are already well documented. There are also instructions for moving an existing WordPress site from one server to another. By combining these together, you can work out how to make a clone of an existing self-hosted WordPress site in a new local test environment.

However, many of the steps are not obvious—especially if you created your live WordPress site via a one-click install, as I did, using Fantastico or similar—and some of the existing how-tos out there aren’t all that clear. Having gone through this process myself, and cloned a live WordPress site to a local Mac OS X environment, I thought it would be useful to describe the full end-to-end process in simple ABC steps.

Strategy

The strategy I’ll follow is to configure the local site as closely as possible to the live one.

We’ll create a local domain, so the local site can be accessed using a normal-looking URL. This is partly for psychological reasons—it looks more convincing—but also because this makes it easier to view the local site from a mobile device such as a phone or tablet, which I’ll cover in a future post.

Throughout these steps I’ll assume that the live site has the URL http://example.com, and for the local site, we’ll define a new hostname for the URL http://exampledev.com.

I will also assume the local WordPress environment will run on Mac OS X. If you’re using another OS, a few of the steps will be different, but the overall principle remains the same and many of the steps will still be applicable.

Setting up a local domain

To allow the local site to be accessed on a URL such as http://exampledev.com, you need to create the domain “exampledev.com” by mapping it to localhost (127.0.0.1) in your local hosts file.

1. Open a Terminal (Applications → Utilities → Terminal.app), and edit the local hosts file (/etc/hosts) using a text editor such as vim:

sudo vim /etc/hosts

2. Enter your password when prompted, and add the new domain name at end:

127.0.0.1       exampledev.com

» reminder In case you haven’t used vim, or forgot how to use it, you need to press i to go into insert mode, make your change, and then press Esc to get out of insert mode. When you’re done, type :wq to save your changes and quit or :q! to quit without saving changes.

Local host entry

Installing MAMP

As the official documentation says, the easiest way to run WordPress on a Mac is probably to install MAMP, which provides a Mac OS X variant of the LAMP (Linux, Apache, MySQL, PHP) stack. So, wanting an easy life, this is the route I took.

MAMP is a single install that gives you all the software you need to run PHP applications such as WordPress on a Mac. If you’re using another OS then you’ll need to find an equivalent way to install Apache, MySQL and PHP.

  • Download the latest version of “MAMP and MAMP Pro” from http://www.mamp.info/. Both MAMP and MAMP Pro get installed together, but you only need to use the MAMP variant which is free.

Once MAMP is installed, open its Preferences dialog. Only two configuration changes are necessary to get going.

ports tab

On the Ports tab, set the Apache port to 80 and leave the MySQL port at 8889.

» note Setting Apache to listen on the standard Port 80 makes the local URLs neater, because there will be no port in the URL, but it requires you to enter your password every time you start MAMP (although you only need to restart MAMP when you reboot your machine). If this is too much trouble, you can change it later — for now let’s just stick with Port 80.

Before setting Apache to Port 80, make sure you don’t have another web server already running on your machine on that port—in particular, make sure System Preferences → Sharing → Web Sharing is turned off (note—this option seems to have been removed in Mountain Lion anyway).

Apache tab

On the Apache tab, choose where you want your document root to be. This can be anywhere you like, but for convenience I put it somewhere in my home directory. For example:

/Users/user/hosting/docroot

Create that folder, if you haven’t already, and click Start Servers to start MAMP’s Apache and MySQL processes. You should be able to see that both Apache and MySQL are running.

MAMP running

At this point OS X may ask Do you want the application “mysqld” to accept incoming network connections? I have found that if you block incoming connections to MySQL, everything works fine—presumably because the incoming connections from MAMP are only from localhost, not other machines. So, if you’re not sure, it should be fine to block incoming connections.

Cloning the live WordPress site

Now that we have the MAMP platform in place, the next step is to clone the live WordPress site on to that platform.

There are only two things you need to copy across in order to completely clone a WordPress site:

  1. Your document root and all the files under it.
  2. The WordPress MySQL database.

That’s it. There are no other secret WordPress configurations or data hidden anywhere else. All the configuration for Apache, MySQL and PHP can be done through MAMP UI, and everything to do with WordPress is carried over when you copy the document root and database.

Incidentally, you can use the same process—copying the document root and database—to make an ad-hoc backup of a WordPress site at any time (either the live site or the local one).

When setting up a web application, I like to start from the front-end and work backwards. This is because when the front-end is done, you can start serving static content and feel like you’re making progress. So, let’s deal with the document root first.

Copying the existing document root

Copy your document root as follows.

  • Log into your hosting provider, find your document root and tar or zip it up, and download the resulting file e.g. docroot.zip to your machine.

Even if WordPress is installed in a sub-folder of your document root, e.g. /blog, you probably want to include the entire document root, including whatever else is there besides WordPress. This allows you to test duplicate your entire web site, and ensures the local site mirrors your live site’s URL structure.

  • Untar or unzip it into the document root you chose above e.g. /Users/user/hosting/docroot/.

» checkpoint Now you should be able to serve static content from your document root.

For example, if you put a test.html file directly in your document root, then you should be able to access it at the URL http://exampledev.com/test.html. This means Apache is working. You should also be able to see the MAMP home page at http://exampledev.com/MAMP/.

However, if you visit a WordPress page such as http://exampledev.com/wp-admin/ you should get the message “Error establishing a database connection“. This is a good thing (for now), as it means the PHP interpreter has successfully run WordPress and attempted to connect to the database. Since the database does not exist yet, you get that error. We’ll address that in the next step.

Exporting the existing database

To copy the WordPress database over, you first need to export it from your live site as an SQL file.

If your hosting provider offers the web application phpMyAdmin for administering MySQL, then you can do this as follows.

  1. Find phpMyAdmin in your hosting provider’s admin UI.
  2. Open your WordPress database by clicking its name in the left-hand navigation bar. For example your database name might be wpdb.
  3. Click Export.
  4. On older versions of phpMyAdmin you need to tick Save as file, otherwise this is automatic.
  5. Click Go.

» note Make sure you select the WordPress database before you click Export. If you just open phpMyAdmin and click Export without first selecting a database, then it exports a whole load of MySQL system stuff which you don’t need.

The above steps should download a file to your local computer called something like wpdb.sql. This is effectively a backup of the entire WordPress database, including all the tables, schema and data.

In a later step you’ll import this SQL file into the local MySQL server installed by MAMP.

Checking how WordPress will connect to the database

Before you import the data, let’s check how WordPress is configured to connect to the database.

  • Open the wp-config.php file that you copied from the live environment into the local document root, and find the following section.
/** The name of the database for WordPress */
define('DB_NAME', 'wpdb');

/** MySQL database username */
define('DB_USER', 'wpuser');

/** MySQL database password */
define('DB_PASSWORD', '************');

/** MySQL hostname */
define('DB_HOST', 'localhost');

This tells WordPress to find the MySQL server running on the machine indicated by DB_HOST, log in with MySQL username DB_USER and password DB_PASSWORD, then use the MySQL database indicated by DB_NAME.

Make a note of the values for each of those fields.

  • Make sure the DB_HOST field is set to localhost in your local wp-config.php file.

It is NOT necessary to set the MySQL port number in the DB_HOST value. MAMP is already set up such that PHP “knows” the correct port for MySQL automatically via a PHP configuration file. If you set the DB_HOST field to just “localhost” it will work fine.

Importing the database

Importing the data is not as simple as just clicking Import in phpMyAdmin on the local machine. The SQL file we generated will not automatically create the MySQL database in the new environment; it assumes an empty database of that name already exists.

So, first we need to create an empty database with the correct name, then import the data.

  1. Go to the local MAMP home page e.g. http://exampledev.com/MAMP/.
  2. Click on phpMyAdmin to open the local phpMyAdmin provided by MAMP.
  3. Find the “
phpMyAdmin: Create DB

You should see a confirmation message “Database <name> has been created.”

Once you’ve done that, you can import the SQL file.

  1. Select the empty database you just created in phpMyAdmin’s left-hand navigation bar.
  2. Click Import.
  3. Click Choose File
  4. Find the SQL file you exported earlier e.g. wpdb.sql.
  5. Click Go.

Importing may take a while if there is a lot of data. Once it completes, you should see a confirmation message “Import has been successfully finished, <n> queries executed.”

This means all the WordPress data has been loaded.

Ensuring WordPress can authenticate to MySQL

Next you need to ensure that WordPress can authenticate to MySQL. For this, you have a couple of options.

OPTION 1: Change your local wp-config.php file so that WordPress authenticates with the DB_USER “root” and DB_PASSWORD “root“.

The MySQL server installed by MAMP has a single default user “root” with password “root”, which has full privileges on all databases. If you want to get going as quickly as possible, enter these details in the DB_USER and DB_PASSWORD fields.

/** MySQL database username */
define('DB_USER', 'root');

/** MySQL database password */
define('DB_PASSWORD', 'root');

Since this is just a test environment on your local machine, the security of the configuration is not critical, so configuring WordPress to use the root account is probably OK. The root account will still exist anyway, whether you use it or not—and changing its password is not easy.

» note If you do feel tempted to change the root password of the MySQL server installed by MAMP, be aware it is a non-trivial exercise, because it’s hard-coded at least 5 different MAMP scripts and config files which are not very well documented.

OPTION 2: Create a new user in the local MySQL server to match the one used by the live site.

Instead of using the root account, you may want to create a new MySQL user in your local environment — especially if your live WordPress site is using a non-root user, in which case you may want to use the same username in the local site. Reasons for doing this might be as follows.

  • The main WordPress configuration file, wp-config.php, can be transported between environments with fewer changes.
  • When you do a database restore in the local site, you’re following a similar process to what you’d do in the live site, so you get to understand and rehearse the process a bit better, in case you need to do a restore on the live site.

If you choose Option 2, then you need to do three things: create the new user, allow it to log in from “localhost”, and give it full permissions on the WordPress database. Here are the steps in detail.

  1. Open the local phpMyAdmin provided by MAMP.
  2. Select the WordPress database in phpMyAdmin’s left-hand navigation bar.
  3. Click Privileges.
  4. Click Add User.
  5. Enter a username, or paste the username from the DB_USER field in wp-config.php, into the User name field in this form.
  6. Select “Local” from the Host drop-down list (this bit is important!)
  7. Choose a new password, and enter it both in the DB_PASSWORD field in wp-config.php, and in the Password field in this form, twice. (Alternatively just copy the existing live password from wp-config.php into this form — but it’s probably better to choose a new one.)
  8. Ensure that Grant all privileges on database “<dbname>” is selected.
  9. Click Go.

phpMyAdmin: Create User

» note If your wp-config.php is using localhost for the MySQL hostname, then you must choose “Local” from the Host drop-down in step 6 above. Strangely, if you leave it at the default value “Any host” then WordPress fails to connect with an “Error establishing a database connection“. Apparently, “Any host” does not mean any host…

Confirming WordPress successfully authenticates to MySQL

Regardless whether you followed Option 1 or 2 in the previous step, everything should now be in place for WordPress to successfully authenticate to MySQL.

» checkpoint You should now be able to see at least the blog’s home page as a visitor would see it at http://exampledev.com (or http://exampledev.com/blog if your site is in a sub-folder). It should look (almost) identical to your live site.

However, there is still one critical thing that needs to be addressed before we can say we’re done:

  • Any links within the WordPress blog still go to the live URL, e.g. http://example.com
  • It’s not possible to log in. The login process redirects you to the login page on the live site.

»note If you have the MAMP Apache listening on a port other than 80, you cannot access WordPress at all at these stage (even on the other port) because it tries to redirect you to port 80 which fails. This is because the site’s URL, as configured in the database, is implicitly expecting port 80.

Fixing the WordPress URLs

The cause of these issues lies within the WordPress database—which was copied from the live site—as the database is still configured to use the live site’s URLs.

WordPress URLs would normally be set in the following places under the Dashboard:

Settings → General → WordPress Address (URL)
Settings → General → Site Address (URL)

However, now we have a slight chicken-and-egg situation. How can you change the site URLs in the database, when you can’t log in to the WordPress Dashboard to do that, because it redirects you to a different URL, because the URLs in the database are wrong?

The easiest solution is to update the site URLs directly in the database in your local site, so that they use the new domain.

  1. Open the MAMP phpMyAdmin tool again.
  2. Select the WordPress database in phpMyAdmin’s left-hand navigation bar.
  3. Click SQL.
  4. Paste in the following, and update the URL values as appropriate.
  5. Click Go.
update wp_options set option_value="<WordPress Address (URL)>"
where option_name="siteurl";

update wp_options set option_value="<Site Address (URL)>"
where option_name="home";

The values you substitute for <WordPress Address (URL)> and <Site Address (URL)> should be identical to those fields in your live site, except with the live site’s domain replaced with the local site’s domain. Keep any URL path e.g. “/blog” the same, if you have one. For example:

update wp_options set option_value="http://exampledev.com"
where option_name="siteurl";

update wp_options set option_value="http://exampledev.com"
where option_name="home";

These two URL fields should fix nearly all the links generated by WordPress, at least as far as basic navigation around the web site goes. This is because for navigation elements, WordPress generally uses relative URLs which are resolved using these two URL fields as the base.

However, media links within blog posts will still be pointing to the live site. There may also be other absolute links that were hard-coded by you or generated by plugins, which are pointing to the live site. They won’t show as broken links though, because your live site is still up and running.

For the purpose of setting up a local environment for testing things out, this may not matter. But if you want to update all the links within blog posts as well, instructions can be found in some of the articles linked from here such as this one.

For additional tips for fixing the URLs—including for WordPress multi-site—see the comment from David Dumonde below.

The end result

After all this, it should now be possible to view the site in your local environment at http://exampledev.com, exactly as a visitor would see it, apart from the new domain.

Furthermore, it should also be possible to log in to the WordPress Dashboard at http://exampledev.com/wp-admin/, using the same WordPress credentials that you use to log in to the live site.

You should now have a fully operational local clone of your live WordPress site.

What’s next?

In the next post I’ll cover how to access the local WordPress site from mobile devices such as phones and tablets, using the same local hostname e.g. http://exampledev.com. I’ll describe a way to do this using only free software, and without jailbreaking the mobile device or changing its local hosts file.