Migrating a WordPress Site from Apache/Linux to IIS/Windows

Jan 11th, 2015

Comments: 0
Category: Uncategorized

Migrating a WordPress Site from Apache/Linux to IIS/Windows

I’m largely a Windows person, but in the search for some decent blogging software to run myself, I ended up with WordPress (frankly the best of a bad bunch) and to get it up and running quickly, I installed it on to the only web server I had around which happened to be Apache on Linux.
I’ve now built a new web server with Windows Server 2012R2 and IIS 8.5, but the challenge was then to migrate several existing WordPress sites to it. Whilst there is some documentation on the Internet, the vast majority of it deals with Apache and Linux. So this is an attempt at consolidation of some of the many articles I needed to read to get it working in IIS. I also attempted just to use native tools as I didn’t have access to cpanel, myphpadmin and similar.
The article presumes you have your own dedicated web servers (at both ends), with SSH access to Linux and RDP to Windows. It also presumes that you are reasonably technical in Windows and know enough about Linux to be dangerous. Installing 7Zip and WinSCP on the IIS server before you start is helpful.
I am also presuming that you want to retain the same domain name – if not there are a couple of extra stages I have put under ‘Notes’ at the end of the document.
Firstly – the majority of the article you can skip if you want to use the MS PI tool to install WordPress. This works brilliantly if you want a very simple install and don’t want to deviate from the ‘happy path’, but if you actually want to understand what you are doing with the underlying technology this will not help you. If you do want to use the Web Platform Installer it is super easy – instructions here http://codex.wordpress.org/Installing_on_Microsoft_IIS and you can skip to the sections on backup and restore. Also it is not made very clear how you actually upgrade the supplied version of PHP – to do this, install the standard package, and then go back into the PI tool, search for PHP and then select the most current version.

First you need to install IIS. Log on to your server as an administrator and go to Server Manager. Click on ‘Local Server’ and then ‘Manage -> Add Roles and Features’. Add Web Server and make sure that you have also selected ASP.NET 4.5 and CGI components under ‘Application Development’. Accept any prompts for prerequisites. You should not need to restart the computer.
Now install the URL Rewrite module which you can get here – http://www.iis.net/downloads/microsoft/url-rewrite

First you need to install the C++ redistributable for Visual Studio Update 4 (or the latest version – this was as of Jan 2015). Note that it is important to install the 32 bit version – even though Windows 2012 is 64 bit. See this article – http://stackoverflow.com/questions/11992153/iis-7-5-php-failure-the-fastcgi-process-exited-unexpectedly for what happens if you don’t.
Now go to the PHP web site and download the latest version – you need VC11 x86 non-thread safe. Extract all the files to c:\php. Make a copy of pnp.ini-production to php.ini in the same directory.
For reasons that are not clear to me – the php.ini provided is not prepped for IIS (why not have an alternate IIS version with the settings pre-corrected?), so you need to edit it and set the following (remove the ; at the beginning of each line as this causes it to be commented out – you do not need to remove the comment character at the start of the section header).
extension_dir = c:\php\ext)
log_errors = On
error_log = C:\inetpub\temp\php-errors.log
cgi.force_redirect = 0
cgi.fix_pathinfo = 1
fastcgi.impersonate = 1
fastcgi.logging = 0
There are other settings to do with memory management you might want to look at, also I would set upload_max_filesize to something more realistic than 2MB (and note that in php.ini it is ‘2M’ not ‘2MB’).

Now add c:\php to the system path by typing ‘environment’ from the start screen, highlighting the ‘path’ variable and clicking edit. Then append ;c:\php\ to the variable and click apply.

Launch IIS Manager and go to the Handler Mapper applet. Click on Add module mapping and fill it in as follows
Request path – *.php
Module – FastCgiModule
Executable – c:\php\php-cgi.exe (note that if you try to use the browse button it only shows you dlls not exes – so you need to type it in manually)
Again in IIS Manager – go to the Default Document applet and click on Add default document with a setting of ‘default.php’. Create the corresponding file in notepad (c:\inetpub\wwwroot\phpinfo.php) with a content of

Restart IIS from the Manager and then go to Internet Explorer and browse to http://localhost/phpinfo.php. You should see a test page open showing you your PHP settings. This proves that PHP itself is working and it is important to confirm this before going on to the next section. Also note that this file should be removed before going into production as it is a security concern.

Download the install files from here – http://dev.mysql.com/downloads/ – you want the latest version of the community server and you will need to register an account with Oracle before you can continue.
Click the MSI file to start the install and then select custom. You then want the SQL server component (64 bit) and MySQL Workbench for managing the server. Personally I would rather use the command line client but the GUI is useful for the more obscure stuff (and the import of the backup). Accept the defaults on the following page (config type should be server if you are installing this on the same machine as IIS – if it is on a standalone you should chose dedicated).
Allow it to be a Windows Service with the default name, to start automatically, and to run as the standard system account.
The wizard should then start the Workbench program and you will see your server.

Download the latest version of WordPress from http://www.wordpress.org/download. Unzip the files (having 7Zip on the server is helpful here as a lot of this stuff is in formats Windows doesn’t typically use) and copy them to a dedicated directory under c:\inetpub\wwwroot (so for example your directory would be c:\inetpub\wwwroot\wordpress).

You now need to prepare a database and a database user ready for WordPress. I find the easiest way is to go to Start, type in ‘MySQL command’ and open the command line client. You could however use the Workbench program or install PHPMyAdmin
Enter the root password to get to the SQL prompt. First create the database (confusingly MySQL calls it a ‘schema’).
Then create the dedicated user and grant it rights to the database
GRANT ALL PRIVILEGES ON wordpress.* TO “wpuser”@”localhost”
IDENTIFIED BY “putastrongpasswordinhere”;

In your wordpress directory you will find a file called wp-config-sample.php – edit this to change the following fields.
DB_NAME: wordpress
DB_USER: wpuser
DB_PASSWORD: whateverpasswordyouchoseearlier
You should also do a find/replace for ‘put your unique phrase here’ and replace each instance with a different random phrase.
Save the file as wp-config.php.
Now open IE and browse to http://localhost/wp-admin/install.php. You should see the WordPress setup screen. Configure this with some test info as you will overwrite this install later.
Open c:\php.ini and check that the lines
are not commented out – if they are – uncomment them. If they are commented out when you start WordPress you will get the error “Your PHP installation appears to be missing the MySQL extension which is required by WordPress.”
OK – so that is everything working with the default settings. Now you need to backup the information from your existing site and restore it on to IIS.

There are three important areas to backup in WordPress: – the MySQL database, the wp-content directory (and its contents!) and the wp-config.php file (if you have custom settings you need to preserve). The wp-content directory is likely to be large if your blog has lots of pictures on it – so plan for this taking some time.
SSH on to the server (putty is a good tool for this).
First, backup the database. You need either to be root, or to put ‘sudo’ at the beginning of each command. The user name, database name and password in the commands below are the ones given to you at the end of the original install of WordPress which (hopefully!) you made a note of at the time.
Make a directory for the backup – mkdir wpbackup
Change to the directory – cd wpbackup
Actual backup command – mysqldump –h localhost –u databaseusername –p databasename | bzip2 –c > backupfilename.sql.bz2
So given a database name of ‘myblog’ and a username of ‘myuser’ the command would be
mysqldump –h localhost –u myuser –p myblog | bzip2 –c > backupmyblog.sql.bz2
It is important to get this exactly right (don’t you love Linux….). If you do you will be prompted for a username and password and then it will (quickly) return to the command prompt. This was so quick on my blog with 200+ entries and 4G in size that I thought it hadn’t worked but it had – you can check to see that the filesize is reasonable (ls –l) and also you can look at the file in a text editor (less filename).
Now you need to zip up the wp-content directory. I’ve never had much luck with working out where Apache keeps its files – but if you search for wp-config.php (find / -name wp-config.php –ls | more) then the directory where it is located is the one where you will find wp-content. Use the Linux tar utility to create an archive (all the files rolled into one) and compress this using bz2. You can run both commands at the same time with the following syntax.
Go to the parent directory for wp-content:
tar –cjvf filenametocreate.tar.bz2 directoryname
So in our example it would be:
tar –cjvf myblogcontentsbackup.tar.bz2 wp-content

Now RDP on to your Windows server and fire up WinSCP. Make a directory c:\wordpressbackups and copy the database and wp-contents backup files you created earlier from the Linux server. Extract all the files using 7Zip. If you are using a VM, this is a good moment to snapshot it with everything working.
Now delete the wp-content directory (and its contents) from c:\inetpub\wwwroot\wordpress and copy over the wp-content directory from the backup.
Go into MySQL Workbench and Go to Data Import/Restore. Select the Radio Button ‘Import from Self-Contained File’ and browse to your database backup.
In the ‘Default Schema to be imported to’ browse to your ‘wordpress’ database. You can ignore the bit on the screen about ‘this is only used if the dump file doesn’t contain its schema’ – I was confused by it but the import seems to work regardless.
Click on ‘Start Import’ – on my machine it finished in less than five seconds.
Go to IE and browse to http://localhost/wordpress/wp-admin just to make sure you can get to the files. If you can – move to the next stage.

Before you do anything irrevocable like changing DNS you should test that the URL is working properly locally. So find out what your internal IP address is (using ipconfig) and then add an entry to c:\windows\system32\drivers\etc\hosts referencing your production URL (the easiest way to do this is to right click the start button – open a command prompt as administrator, and then execute ‘notepad c:\windows\system32\drivers\etc\hosts’. The entry should look like: www.wordpresstest.com
Now go into IIS Manager, right click sites and go to ‘Add Website’. Site name can be any descriptive name, physical path should be to the top level directory where you installed WordPress (eg. c:\inetpub\wwwroot\wordpresstest. Then in the ‘host name’ field – add the actual URL you want to resolve – eg. www.wordpresstest.com. The website should start immediately without needing an IIS reset.
You should now be able to browse to the ‘real’ URL. Presuming that you can and that everything else is working, you can now change DNS to point at your new server.

If you are using the pretty permalinks feature (i.e your links look like www.testdomain.com/thisisapost rather than having a numeric id in them), there is an extra stage you need to carry out. Firstly, make sure you have the URL rewrite module installed in IIS. Then you need to create a web.config file in the directory where WordPress is installed (i.e the parent directory which contains wp-content etc). The web.config file should look like this:

After creating the file, restart IIS and it should start to work. Note that if you get the syntax of the file wrong such that IIS can’t recognize it (by not closing off the tags properly for example) the entire application may not work.

1. I’ve presumed you are actually migrating your domain name with the contents of your blog – i.e that once you are running on the new server you will change DNS to point at it. If you are moving to a brand new domain name – you need to run some SQL commands. From an SQL command prompt run the following:-
UPDATE wp_options SET option_value = replace(option_value, ‘http://www.olddomain.com’, ‘http://www.newdomain.com’) WHERE option_name = ‘home’ OR option_name = ‘siteurl’;
UPDATE wp_posts SET guid = replace(guid, ‘http://www.olddomain.com’,’http://www.newdomain.com’);
UPDATE wp_posts SET post_content = replace(post_content, ‘http://www.olddomain.com’, ‘http://www.newdomain.com’);
UPDATE wp_postmeta SET meta_value = replace(meta_value, ‘http://www.olddomain.com’, ‘http://www.newdomain.com’);

2. If you use the method above you should not need to copy your wp-config.php from the old server to the new one, because you have pre-created the new one with the correct values for database name etc. However if you have made custom changes to the original, you need to reapply them on the new server.

3. Microsoft Web Matrix. If you use this (rather nice) tool for development locally – do not use the method I have described above to move the site unless you absolutely have to (you should use the Web Deploy option within the tool itself). The reason for this is that your WordPress database will contain references to eg. http://localhost:5678 and after it has been migrated it will still attempt to redirect to a random high port which IIS does not have open. Having said this – it is fixable albeit in a scary way. Open the database associated with the site in a tool of your choice (I used MySQL Workbench). Go to the wp.options table and modify the ‘siteurl’ and ‘home’ fields to reflect the new values. For example:-
siteurl (original) – http://localhost:4451
siteurl (modified) – http://www.wordpresstest.com
In the same way, you need to change the ‘upload_url_path’ to where ever you store your images (typically http://www.wordpresstest.com/wp-content/uploads). Dependent on what theme and features you are using – you may need to change other settings as well. There is a good article about this here http://codex.wordpress.org/Changing_The_Site_URL although I did not find that I needed to change anything on the individual blog postings. It goes without saying that if you do need to do this that you back your database up first.

4. If you need multiple WordPress sites on the same server, you can either install multi-site (which only works for sub-domains or sub-directories of the main domain), or you can just have multiple installs of WP on the same IIS server. I went for the latter, and discovered that for second and subsequent sites you don’t need most of the instructions above. PHP and MySQL are already installed, so you need to create a new database, create a user and grant user rights, and then import the data. Copy the content data over and then create a new website in IIS referencing the new URL.

5. If you are using photos on your site you need to use ‘Image Magick’ to get them to scale correctly. I used this article – http://stackoverflow.com/questions/2858439/installing-imagemagick-extension-with-php-windows You also need to go into your php.ini and uncomment the line “extension=php_gd2.dll”. This was very fiddly and difficult to get to work so you may have to do some playing around. The critical thing is to make sure that the version of image magick exactly matches up to the version of php you are using.

6. I used the following articles (amongst others) to write this, so thank you to the authors for their well-written help.


Add a comment

Your email address will not be shared or published. Required fields are marked *