One thing that I have to do fairly frequently is to move a WordPress site from one server to another. Examples of this can be moving a site from staging to production or production to my local environment. There are a lot of ways to do this but I thought I would document my process. The workflow I am going to walk through assumes that you have shell access to the server in both the source and target locations.
The first thing that I do is back up and archive the files that I want to move to a new location. The transfer of files will be much more efficient when downloading one large archive file then if downloading each file individually through FTP. It is my understanding that repeatedly connecting for small individual files via FTP really slows down the transfer of the files. When connected to the source site’s server through SSH, I will tar and gzip the site’s folder to create a single file containing all my site’s files. Here is the command that I use:
tar -zcvf website.tar.gz public_html
This command will take all of the files in
public_html and compress them into a new archive file called
website.tar.gz. Of course I will replace “website” in my archive file name with something representing the site I am actually transferring to avoid confusion. Let me explain the command above in a little more detail.
First, I am using Unix’s tar utility to package up my website’s folder. I am sending four flags to tar, z, c, v, and f. What do these do? Well, you can find the full documentation for
tar on the command line by simply typing
tar man. But these particular flags do the following:
- z – Tells tar to use gzip to compress the archive it creates with the files. So, it will take the single resulting file and compress it to a smaller size. That is also why I name my file with the
.gzextension to denote it as being processed with gzip.
- c – This simply lets
tarknow that I am creating a new archive file.
- v – The v flag is totally optional. It just turns on “verbose” output so you will see what your command is currently doing and let you feel like you’re starring in The Matrix as the list of processed files quickly scrolls by in your terminal.
- f – Tar is instructed to write to the specified file. In my case, this is
There are a couple of things that I will check at before creating the archive.
- Is there enough drive space on the server for the resulting archive? Obviously, you will need to have enough room on the drive for your site’s archive file.
- Are there full site backups of the site or other unnecessary large files within your site’s folder? For example, it will make your site’s archive a lot larger than needed if you are including multiple copies of the site in the archive file. Many WordPress backup plugins will create backups in the
wp-contentdirectory. The verbose flag can help determine if there are any huge files in the site directory as the output will pause when
taris working on a large file like a backup or Photoshop file. Another example of a directory you don’t necessarily need is the
node_modulesdirectory. You could recreate these from the
package.jsonfile if needed.
With tar, you can exclude certain files from the archive. Here is an example of creating a tar archive of a site without the
tar --exclude "public_html/wp-content" -zcvf public_html.tar.gz public_html
After the archive is created, I will list the contents of the directory just to make sure it looks like the resulting file was created correctly.
Obviously, if the file size is 0 or very small, you will know that something likely went awry.
Now we have our site files. The other thing that we will need is the site’s database. Since we are already at the command line, I will just run a
mysqldump command to generate a SQL file. Another option would be to use a tool like phpMyAdmin to simply export the database.
If I don’t remember the database credentials, I will open up the
wp-config.php file on the command line. I use the
less command for something this simple but you could also use
nano, or something else.
I will open up a text editor to store the database name, user, and password from the
wp-config.php file for easy access.
If you haven’t used
less in the past it is helpful to know that you can exit out of it by hitting the
With the credentials stored in a handy location, I will create the
mysqldump command and run it from on the server where I created my site archive.
mysqldump -u root -p'root' -h localhost local > local.sql
This command simply passes in the username (
-u), password (
-p), database name (
local), and tells it to dump the database to a file called
local.sql. I wrap my password in single quotes to handle any special characters that otherwise would need to be escaped. Again, I will verify that the resulting SQL file makes sense size-wise by listing the files in the directory.
We now have the files that we need to stand the site up on another server. I transfer them to the target location using an FTP program like Panic’s Transmit. I put the files on the same level as the source site’s folder. For example, let’s say I have created a site using Local by Flywheel on my laptop. The folder structure that Local uses for websites is:
<Local Sites Directory>/<site name>/app/public
public folder is the root of the WordPress site where your
wp-config.php file lives. My file structure will look something like this:
Since Local by Flywheel helpfully creates the
wp-config.php file for you, I like to keep that. After all, your credentials for the site on the production or staging server will be different. So I copy the
wp-config.php file outside of the site’s folder that will soon be replaced.
mv public/wp-config.php .
The above command will move the
wp-config.php to outside of the site folder to where you are working.
Now we are ready to move the website’s files into place. You can remove the the starter site that Local created for you now that
wp-config.php has been moved out. I will delete the folder:
rm -Rf public
Be very careful with this command. It will totally delete the
public folder. If you have multiple tabs open in your SSH program you will want to be absolutely sure you’re in the correct place and not deleting your production website.
With the old site gone, I extract my archive file to create the site directory:
tar -xvf website.tar.gz
The v and f flags are the same as before. But instead of creating a new archive and compressing it, we are extracting the archive with x.
Something to keep in mind is that Local by Flywheel uses the directory
public to hold the website. Many other hosts tend to use
public_html. So if there is a discrepancy, you will need to rename the extracted folder. If my production host uses
public_html and I am moving it to my Local by Flywheel site I will just rename it using the
mv public_html public
I will then move the
wp-config.php file into the extracted site’s folder to ensure we have the correct database credentials and WordPress configurations for the site.
mv wp-config.php public/
This will replace the configuration file from the source website. But this just gets us ready to read the database. We still will need to import the SQL file from the site we are moving.
I delete the existing database tables for the site. I do this using my favorite MySQL client, Navicat. You could also use phpMyAdmin or Local’s included tool, Adminer.
Now, import the SQL file that you created from the source site. I also will do this in Navicat. You could also do this in other tools or directly from the command line using MySQL if you have MySQL available on your command line:
mysql -u root -p'root' local < database.sql
The above command specifies the username, password and instructs the command to replace the database,
local, with the contents of
We now have site files set up and a configuration that will read the imported database. We need to make a couple changes to our database content first, though, using a MySQL client tool. Specifically, we want to modify WordPress’s settings for the site’s address. If we were to try to go to our new site with the freshly-imported database we would be redirected to our source site. So, let’s open up the
wp_options table in our MySQL client. We will look for two records – the records with
option_name values of
option_value for these records, which will likely be near the top of the
wp_options table, will be the source site’s URL. Change the
option_value to your new site’s URL:
With that done, we can go to our new site’s WordPress admin. In the above example, I would go to http://starter.local/wp-login.php. Because we copied the database from the source site, the users will have been moved over to the new location. So any administrator you had at the existing website will be valid at your site’s new instance. So go ahead and log in!
We replaced just two instances of the site URL to represent the site’s new location. But other existing fields will still reference the source location. So, if you were clicking around the copy of the site, you will soon follow a link back to the source site. We need to update the URL in all of our database’s records. To do this, I will often install Delicious Brain’s Better Search Replace plugin.
There are other tools that you could use to update the URLs in your site’s database. One notable option would be WP CLI which allows you to make the replacements on the command line. In fact, if you have access to WP CLI, you could also use it to remove all the tables from your database, import the SQL file, and replace your URLs all from the command line. So you could likely write a shell script to do a few steps in a single command.
With the URLs updated, you should be all set to use the copy of your site. If your site is broken, one thing to check would be your
.htaccess file in the root directory. Sometimes a host will have server-specific settings in there that will not be compatible with your new server. A common example I see is when a version of PHP is specified. Another file that can commonly cause trouble is the
php.ini file which, again, sets up host options that might not work with the destination server.