How To Migrate WordPress from Shared Hosting to a Cloud Server with Zero Downtime


I have been a customer for several years and generally speaking I have been pleased with the services I got from Bluehost. Recently I noticed some annoying variability in response time which appeared to be directly related to the shared host arrangement. I did a little shopping and found that for almost the same monthly price I could get a virtual server at DigitalOcean.


My primary objective was to migrate two shared host WordPress blogs and an open source web-based news feed (RSS/Atom) reader called Tiny Tiny RSS from Bluehost to a virtual server at DigitalOcean. A secondary objective was to replace my web analytics with Piwik.

My Plan

My plan was to follow the DigitalOcean tutorial, How To Migrate WordPress from Shared Hosting to a Cloud Server with Zero Downtime, with a couple of changes. The tutorial was written for Ubuntu 12.04 LTS and I would be installed 14.04 LTS. Since I am a Windows guy I would be using Putty for SSH sessions and WinSCP to transfer files.

Step 1. Create a Backup

The biggest change I made in this step was to backup of the entire WordPress folder. Several services asked me to put little files in the root directory as part of the approval process. I also have a customized .htaccess file. Since my copies of WordPress are up to date, it was easier and faster to copy over the entire folder.

Step 2. Set Up the Cloud Server with LAMP Stack

Here :

  1. I followed the first four steps of the tutorial, Initial server setup for Ubuntu 14.04, but if I had to do it over again I would go ahead and configure ssh to restrict root login and explicitly permit certain users. Considering how many folks will be trying to break into your server, you might as start locking down the server.
  2. Next I followed the tutorial, How To Install Linux, Apache, MySQL, PHP (LAMP) stack on Ubuntu 14.04.
Step 3. Install WordPress

Since I was going to restore the entire WordPress folder I skipped this step.

Step 4. Create a Virtual Host

In this step I started to follow the tutorial, How To Set Up Multiple WordPress Sites on a Single Ubuntu VPS. In my case I was going to use a wordpress folder under the default directory for the main blog and a second folder under www for the second blog. I created two virtual host files, and, for my two blogs. The original tutorial omitted the conf extension.

Step 5. Restore Database and Files

This is when I learned the most important lesson. My first Mysql backups were incomplete or bad when I tried to load them. I had poor results trying to load compressed files. So I made it simpler.

  1. I saved the Mysql backups to a temporary folder
  2. I compressed them.
  3. I transferred them to the new server.
  4. I uncompressed them.
  5. I created the database and user.
  6. I loaded the uncompressed file.

To restore the WordPress files :

  1. I transferred the compressed file to the server.
  2. I uncompressed the file in the home directory.
  3. I copied the files to the web server using:
    sudo rsync -avP wordpress/ /var/www/html/wordpress/ 
    sudo rsync -avP firstsite/ /var/www/firstsite/
  4. Give ownership of the directories to the Apache web user and then add your linux username to the web group:
    sudo chown www-data:www-data * -R
    sudo usermod -a -G www-data linux_user_name
  5. Configure each wp-config.php with the new Mysql usernames and passwords for the databases you just loaded.
  6. This is a good time to make sure that the WordPress permissions are set correctly.
    sudo find . -type f -exec chmod 644 {} +
    sudo find . -type d -exec chmod 755 {} +
    sudo chmod 600 wp-config.php
Step 6. Test your Blog

For me everything worked except for mail and some hard coded links in the widgets. To solve the mail problem I installed the wordpress plugin, WP-Mail-SMTP, and sSMTP for a simple and lightweight MTA for the system messages. All of my messages are sent through Gmail.

Step 7. Update Your DNS Settings

If you are using a CDN like Cloudflare that is linked to your Bluehost account, this would be good time to deactivate it. I did not and the response time was all over the map for a day.

Step 8. Install phpMyAdmin, Piwik, Fail2Ban, and Logwatch
  1. I did not need to install phpMyAdmin but DigitalOcean does have a pretty simple tutorial showing how to install it.
  2. I was originally planning to install Awstats but Piwik looked like a better choice. The 5-minute Piwik Installation was easy.
  3. After a little browsing of the auth.log it was easy to see that there was too much SSH traffic that was not originating from me so the solution was to follow this tutorial, How To Install and Use Fail2ban on Ubuntu 14.04. After running Fail2Ban for a couple days it became apparent that I needed to permanently ban some folks. I followed the tutorial, Permanently Ban Repeat Offenders With FAIL2BAN.
  4. Obviously I needed to look at the log files on a daily basis until I get this SSH hacking under control. The solution in this case was this tutorial, How To Install and Use Logwatch Log Analyzer and Reporter on a VPS.
  5. The first thing I noticed from looking at the authentication failures in the pam_unix section was that some of the folks were spacing out their probes to get around the default settings for Fail2Ban. So I expanded the findtime and bantime and maxretry. This caught some more hackers but it still was missing some others.  So I brushed up on my grep, awk, and bash coding to find the worst of the bunch and ban them. Sorry China! There is something odd about restarting Faile2Ban.  It looked it was working but it was not banning IPs I thought it should. Sure enough when I rebooted the server it would read the log file and immediately ban the IP.
Step 9. Take a Snapshot and Project Wrap-up

At this point I can say that the migration is complete. The sites are working and I fixed all of the configuration issues that showed up in the log files.  The response time for the sites is much faster than on the shared host even though I added another application, Piwik. It looks like I can easily support another blog. I have another blog with a renewal date a couple of months from now.

The last thing to do was to take a snapshot or backup. So I took a manual snapshot as outlined in this tutorial,

How To Use DigitalOcean Snapshots to Automatically Backup your Droplets, and it took about five minutes to complete.

For fun I charted the IPs I had already banned by country.