« Previous: What is Professional Software Development?    Next: Local Variable Declarations »

Running WordPress 2.0 under IIS

WordPress is the blogging / content management software I use to run this site. WordPress was designed to run under the Apache web server. However, the hosting company for my website uses Microsoft's IIS web server to serve most content, including PHP files which WordPress uses. Setting up WordPress to work under IIS was non-trivial, particularly since existing instructions on the web were for version 1.5, while I wanted to run the recently released version 2.0. So I thought it would be helpful to describe the steps I took.

All examples use my website, in which I have WordPress running under a subdirectory of the domain (www.basilv.com/psd) instead of directly under the root. So WordPress itself is installed in directory /psd under my root website directory. Take this into account when using my examples.

First, a little about how WordPress works. WordPress serves all normal content via the index.php file. Given a URL such as http://www.basilv.com/psd/index.php/blog/category/miscellaneous/, the WordPress code called by index.php parses out the path after index.php (/blog/category/miscellaneous) and displays the content associated with that path.

The first problem running under IIS is that the above URL is interpreted to be pointing to a directory - index.php is considered a directory instead of a PHP file to be invoked. To change this behavior, a php.ini file must be created and placed in the website root directory with the following contents:

cgi.fix_pathinfo = 1
cgi.force_redirect = 0

The second problem I encountered is that the .htaccess file provided by WordPress is considered invalid by IIS - it serves a HTTP ERROR 500 whenver trying to access anything in a directory containing an invalid .htaccess file. The solution is simply to delete the file.

WordPress may somewhat work at this point, but with 'ugly' URLs containing index.php in the middle. I wanted clean URLs, so had configured WordPress to use nice permalinks. My permalink structure is /blog/%year%/%postname%. The .htaccess file provided by WordPress uses the Apache mod_rewrite module to convert (rewrite) 'clean' URLs to include 'index.php'. (By the way, this is a big improvement over WordPress 1.5, which required quite a complex .htaccess file which WordPress had to update every time a page was added.)

To use clean URLs, we therefore need URL rewriting capabilities in IIS. The solution is to have the ISAPI_rewrite module installed on the IIS server. With this module running, a httpd.ini file can be added to the root website directory (not under /psd, where the .htaccess was located) with the rewrite instructions.

Unfortunately, the ISAPI_rewrite module is not 100% compatible with the Apache rewrite module, and in particular is missing some (many?) of the capabilities found in the Apache module. Therefore, the conversion from .htaccess to httpd.ini is non-trivial. Let's look at the .htaccess file found in the /psd directory:

RewriteEngine On
RewriteBase /psd/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /psd/index.php

The main lines are the two lines starting with RewriteCond plus the RewriteRule line. What these 3 lines are saying is that for any URL that is not a file (!-f) or a directory (!-d), replace the first character of the URL with /psd/index.php. In conjunction with the RewriteBase line, this essentially converts a URL of the form www.basilv.com/psd/foo/bar to www.basilv.com/psd/index.php/foo/bar.

Directly converting this to ISAPI_rewrite is not possible, because ISAPI_rewrite's RewriteCond directive doesn't support the is-a-file (-f) or is-a-directory (-d) tests, and the RewriteBase directive isn't supported at all. So I wrote rules to convert all URLs starting with /psd to add in the index.php:

RewriteRule ^/psd/$ /psd/index.php [L]
RewriteRule /psd/(.*) /psd/index.php/$1 [L]

This worked, partially. The problem is that images and style sheets associated with the theme were not being loaded, because their URLs were also having the index.php added. I also had some images and files outside of wordpress, but under the /psd directory, that were also incorrectly being rewritten. So I had to add rules for each of these cases before the above rules to map such URLs to themselves and then terminate (the last rule option [L]) before reaching the above rules to add in 'index.php'. Essentially, this is a manual implementation of the RewriteCond rules used in .htaccess to ensure that files & directories do not have their URL mapped. The relevant portion of my final httpd.ini file is:

[ISAPI_Rewrite]

# Rules to ensure that normal content gets through
RewriteRule /psd/software-files/(.*) /psd/software-files/$1 [L]
RewriteRule /psd/images/(.*) /psd/images/$1 [L]
RewriteRule /psd/favicon.ico /psd/favicon.ico [L]

# For file-based wordpress content (i.e. theme), admin, etc.
RewriteRule /psd/wp-(.*) /psd/wp-$1 [L]

# For normal wordpress content, via index.php
RewriteRule ^/psd/$ /psd/index.php [L]
RewriteRule /psd/(.*) /psd/index.php/$1 [L]

When working on the rewrite rules in the httpd.ini file, I ran into problems testing due to the browser cache. I was getting inconsistent / unexpected results due to the browser caching prior results. The solution is to clear the browser cache, which in Firefox can be done via the menu item Tools | Clear Private Data.

Another issue is having WordPress send emails (i.e. when a comment is waiting for moderation). The default approach used by WordPress doesn't appear to work under Windows. The solution I found is to install the wpPHPMailer plugin which allows you to configure WordPress to use any SMTP server to send the emails.

One issue I was unable to resolve is a problem with the post preview feature. Under IIS, post preview doesn't work (due to a 404 error) when the article is in draft status. The workaround is to change the status to private if you want to preview your post. This problem is due to a defect in WordPress that is fixed in WordPress 2.0.1.

To summarize the steps to get WordPress 2.0 working under IIS:

  1. Add php.ini file to correctly resolve URLs containing index.php.
  2. Remove .htaccess file which IIS can't handle.
  3. Install ISAPI_rewrite module on IIS server to provide URL rewriting capabilities.
  4. Provide httpd.ini file to rewrite URLs.
  5. Install and configure wpPHPMailer plugin for sending emails.

If you find this article helpful, please make a donation.

53 Comments on “Running WordPress 2.0 under IIS”

  1. Petit says:

    Very good and clear walk through of a rather complicated matter.

    I think this solution should be part of the WordPress documentation and certainly the installation readme.

    ( Even if it violates the Famous 5-minute install :)

  2. I’ve edited the article to note that the problem with the post preview feature under IIS has been fixed in WordPress 2.0.1

  3. javagirl says:

    Curious as to why you chose WordPress? Did you look at Pebble or blojsom [java based blogging tools]?

  4. I don’t recall coming across any java-based blogging tools like the ones you mentioned when I did my search for blogging software. Besides the functional requirements, I was looking for open-source software with a strong, active community, and WordPress certainly qualifies in that area. Considering how many ISPs support PHP but not Java, I think PHP-based blogging software is just going to have a broader marketshare anyways (than Java-based blogging software), which means a bigger community of users.

  5. marc says:

    I cannot get the first step of this procedure to work on my IIS 5.1 / PHP 5 / Wordpress 2.0 install. PHP is installed as an isapi DLL and seems to be working just fine. However, if there is a path that extends past the index.php (such as http://thehost/wordpress/index.php/category/news/), IIS returns a 404. It’s as though IIS is treating the index.php as a folder instead of passing control to this php file. I have installed urlscan and set the AllowDotInPath parameter to 1, just to make sure this wasn’t the problem. As per your instructions, I tried putting a php.ini file with the two entries you mentioned into my \Inetpub\wwwroot\ folder, but I am still getting 404 errors.

    Is there any basic configuration of IIS or PHP that I need to do so that index.php does not get treated as a folder? Thanks so much for all the help!

  6. It sounds like IIS / PHP isn’t recognizing the php.ini file. I’m not sure what the cause might be – it sounds like you have it in the correct directory. Have you tried restarting your webserver and clearing your browser cache, to ensure that caching isn’t causing problems?

  7. marc says:

    Hmm… it is strange. Here is what my IIS logs look like when I request “http://localhost/sample/sample.php” and then request “http://localhost/sample/sample.php/junk” one after another:

    #Version: 1.0
    #Date: 2006-03-29 21:19:47
    #Fields: time c-ip cs-method cs-uri-stem sc-status
    21:19:47 127.0.0.1 GET /sample/sample.php 200
    21:20:19 127.0.0.1 GET /sample/sample.php 404

    Note that it does not say “/sample/sample.php/junk” in the second line, even though that is the path I requested. It appears that IIS/PHP “knows” to ignore the /junk at the end of the path, yet it still returns a 404 error. I wonder if there is any weird IIS setting that might be preventing me from serving up requests of that form? (Or alternatively it might just be the IIS logging mechanism that drops everything past sample.php when parsing the path…)

    Is there any way to test to see if php.ini is getting read properly? Can I just drop those two lines into my main php.ini file? How could I test to see that this file is getting read in by PHP/IIS?

    I have been using iisreset from the command line to restart IIS and have been clearing my browser cache.

    Thanks again for all the help!!

  8. I’m out of ideas. For myself, I knew php.ini was working properly when URLs of the form /psd/index.php/blog/… were resolving without 404s. I didn’t have to do anything extra besides drop in the php.ini file, but I was using the IIS server of my ISP, so I don’t know if anything special is needed with regards to IIS / PHP setup. I’d try the WordPress support forums, or maybe a google search.

  9. marc says:

    I think I figured it out– PHP needs to run as CGI and not ISAPI extension. I am not sure why one worked and not the other, but everything seems to be working now. Thanks a ton for all the help!

  10. Dany says:

    Hi there,

    Thanks so much for the great instructions! It all worked beautifully except for one thing! Yeah, unfortunately there’s always one exception :(

    I can’t seem to access my xmlrpc.php anymore. I use Zoundary BlogWriter and now I can’t log on anymore. It seems the RewriteRules are missing something for this. I’m useless at RegEx and was wondering if you can help me with this?

    Thanks.

  11. Under the current rules, the URL /psd/xmlrpc.php is getting mapped to /psd/index.php/xmlrpc.php which WordPress doesn’t understand.

    You need to add a rule to avoid mapping xmlrpc.php. Add the following line before the comment “# For normal wordpress content, via index.php”:

    RewriteRule /psd/xmlrpc.php /psd/xmlrpc.php [L]

  12. Dany says:

    Magic! That did the trick! Just like that, huh? :o) Thanks again for the help.

  13. Anni Poulsen says:

    I am about to give up on custom URI for my permalinks.

    I’ve installed WordPress 2.02 on a shared Windows2003 server, which runs IIS6 and PHP4.

    I’ve tried all the tricks I could find listed when searching in Google and WordPress, but I still get a 404 error.

    Being on a shared server I don’t have access to the server itself, but I’ve created the recommended php.ini file in my root dir. I’ve then saved the following permalink strukture:
    /index.php/%year%/%monthnum%/%day%/%postname%/. But I cannot get it to work, all I get is a 404. Does anyone have any suggestions?
    Thanks.

  14. I don’t know what would be the problem, but here are some suggestions. Make sure you can access /index.php correctly by itself first. If you then get 404s when trying to access the full structure (i.e. /index.php/2006/04/test-post-title), then it is possible that the php.ini is in the wrong directory (although it sounds like you have it in the correct directory). You may want to check the PHP4 documentation to see if anything special needs to be done to get the server to recognize the php.ini file.

  15. Great article!
    I was able to translate all wordpress .htaccess rules to the functional replacements for ISAPI_rewrite.

  16. Rocco says:

    Hi, I get an error “Your PHP installation appears to be missing the MySQL which is required for WordPress.” when trying to do do this, I don’t even get as far as the specific errors you discuss. do i need a specific version of the php installer?

  17. Sounds like you are missing a MySQL library for PHP. Check the PHP documentation, or try searching the wordpress forums.

  18. dwille says:

    I found the following to be useful when configuring WordPress to work with Windows XP, IIS 5.0 and PHP 5.1.6. I assume that IIS already serves up PHP pages and you’re getting the “Your PHP installation appears to be missing the MySQL which is required for WordPress” error.

    1. Go to http://dev.mysql.com/downloads/ and select “MySQL Connector/PHP”

    2. Download both the mysqli and mysql extensions.

    3. Move the files that begin with “php_” to your extensions directory (usually c:\php\ext). Overwrite the existing files since these are NEWER and the LATEST from MySQL.

    4. Move libmysql.dll to your PHP directory (C:\php). Overwrite the existing file (the one you’ve downloaded is NEWER). Both ZIP files will have the same libmysql.dll since after PHP 5.0.2 both the mysql and mysqli extensions use the same file.

    5. Edit your php.ini file (in C:\php). Ensure the following lines exist and are NOT commented out:

    extension=php_mysql.dll
    extension=php_mysqli.dll

    6. Ensure your extensions directory is set as well in the php.ini file:

    extension_dir = “C:\php\ext”

    7. Configure Windows so it can find PHP, its DLLS, and the php.ini file (this was the CRITICAL step for me, especially the PHPRC variable I describe):

    Click Start -> Control Panel
    Double-click System
    Select the “Advanced” tab
    Click the “Environment Variables” button
    Under the “System variables” section, click the “Path” variable
    Click the “Edit” button
    Add “C:\php” to the path (no quotes). Note that each path is separated by a semicolon. Also, you should preferably add this EARLY in the path, since some of the MySQL DLLs may be included in other locations on your computer, and you’d like PHP to find the one installed in C:\php before it finds any other.
    Click “OK”
    Now, click the “New” button (again, in the “System variables” section)
    For variable name, supply “PHPRC”
    For variable value, supply “C:\php”
    Click “OK” repeatedly until you’ve got all the windows closed.

    8. Restart the computer so that these settings will be loaded and recognized by PHP. You can verify that your correct php.ini file is being loaded by testing a simple PHP page with the following:

    If your settings are correct, you should see that “Configuration File (php.ini) Path” is “C:\php\php.ini” on the resulting page.

  19. Great comment – thanks!

  20. Chri says:

    This is a great tutorial.

    But unfortunately it didn’t work out so well for me…

    If anyone can help I have a query here:
    http://wordpress.org/support/topic/93010

  21. Does this all still apply with the latest version of WP? I don’t even have a .htaccess file in my download anywhere. And it appears that the file structure in the download is not the same as what you referenced. Everything is in wp-admin, wp-content, wp-includes.

    Thanks for any advice. Maybe now WP just runs under IIS without any mods? I wish?
    Cliff

  22. Yes, this still applies to the latest stable version of WordPress (2.0.5), although as you noted the .htaccess file is no longer included in the download.

    The file structure I reference in my article refers to the virtual structure (i.e. permalink structure) used by the posts and pages, not the physical structure of the WordPress files, which as you note are mostly contained in the wp-admin, wp-content and wp-includes directories. So that may have confused you.

  23. AndyToo says:

    Thanks Basil, your post helped me solve my permalink problems. Good going!

  24. Andre says:

    Hi Basil – great post. I’ve solved almost all of my rewrite problems for my switch to IIS.

    Q: When I intentionally enter a fictitious URL (e.g. http://mywebsite.com/ewruewyruieyruiewyriu.php), WordPress resolves to my home page, and not to my 404.php page.

    Do I need to add a line to the httpd.ini file to get this to work, or is there possibly some conflict with the way IIS handles 404 errors?

  25. Thanks, Andre. I never did solve this problem, but I believe the issue lies with WordPress. If you check your web server logs, they should show that such invalid URLs are treated as normal requests, not 404 errors, so it shows that WordPress is receiving and handling the request.

  26. Darren Hall says:

    Hi, this worked great, until I moved everything to the root folder!

    I changed the code to:

    # Rules to ensure that normal content gets through
    RewriteRule /software-files/(.*) /software-files/$1 [L]
    RewriteRule /images/(.*) /images/$1 [L]
    RewriteRule /favicon.ico /favicon.ico [L]

    # For file-based wordpress content (i.e. theme), admin, etc.
    RewriteRule /wp-(.*) /wp-$1 [L]

    # For normal wordpress content, via index.php
    RewriteRule ^/$ /index.php [L]
    RewriteRule /(.*) /index.php/$1 [L]

    Links to posts work fine, but links to categories just bring up the home page. Any suggestions? Thanks!

    Darren

  27. Hi Darren,

    I don’t see anything obviously wrong. It may depend on the permalink structure you defined for categories. Try navigating to the category URL with index.php added first: i.e. yourhost.com/index.php/category/some-category, which will verify that your category URLs work as expected. Then comment out all but the last rewrite rule, and see if categories work. Assuming they do, you can narrow down the rule that causes them to fail.

  28. Can any one send me a complete working httpd.ini file for wordpress ISAPI?!

  29. Hi Pieter,

    The contents of your httpd.ini file will depend upon your WordPress setup – i.e. the permalink structure and root directory (if any).

  30. http://www.nerdt.nl/blog is my URL for the blog and I haven choosen any permalink structure jet!

  31. Mark Mills says:

    My ISAPI filter problem – How I fixed it – Remaining Security Questions:

    Wordpress ISAPI filter creating many Application log errors 2268 and 2214

    So I then (most hazardly and without web security in mind) added the Wordpress users “site_name_Anon” and “site_name_Admin” to the IIS_WPG user Group (it is creatd by W2k3 by default) and I also gave the user IIS_WPG “read” and “execute” permissions to the WordPressPlugin.dll file. My Permalinks and ISAPI WordPress Filter now work

    The question I have now is: What security holes have I created?

    ******************************
    Why I did what I did:

    I had gone to the following site to troubleshoot my ISAPI WordPress Filter problem.

    http://blogs.msdn.com/david.wang/archive/2005/06/21/HOWTO-Diagnose-and-Fix-Common-ISAPI-Filter-Installation-Failures.aspx?CommentPosted=true#commentmessage

    It educated me and I learned that my error was :
    Data: 05 00 00 00 -Win32 error 5 – NET HELPMSG 5 returns “Access is denied.”

    The article then mentions:

    “For IIS6 in worker process isolation mode, the process identity is configurable and is at least a member of the IIS_WPG group” (see more on the link)

    That’s when I got the idea to add the Wordpress users “site_name_Anon” and “site_name_Admin” to the IIS_WPG user Group (it is creatd by W2k3 by default) and I also gave the user IIS_WPG “read” and “execute” permissions on the WordPressPlugin.dll file.

  32. Thanks for this resource, Basil. I have a really frustrating situation with getting WordPress on IIS with ISAPI_Rewrite to properly display a 404 page and return the correct status code. Based on a quick test of your blog, it looks like you have the same issue. :)

    The problem: WordPress always returns a status code of 200 (valid page) even when the page doesn’t exist (you can use a tool like this one to test the header status codes your site is returning – http://www.rexswain.com/httpview.html – so input something like this and you’ll see what I mean: http://www.basilv.com/psd/blog/nothinghere).

    You can also confirm the problem by visiting that link and in your case, it shows the main page of your blog. In my case, it shows a page similar to failed search results. For example: http://www.articulate.com/blog/nothinghere

    This is especially important in my case since my Google Mini is indexing pages that don’t exist (http://tinyurl.com/23rs9n) – pulling URLs from the top level of my site and appending them after the /blog/. Google Enterprise support tells me it’s due to the fact that I’m not properly returning the 404s as I should.

    Any ideas at all how to get WordPress/IIS/ISAPI_Rewrite to display my WP 404 page when it should, and to return a proper 404??

    Thanks in advance!

  33. Hi Gabe. Congrats for determining my site doesn’t properly return 404 error statuses. As you noted, it also doesn’t properly resolve bad URLs to the error page, but just shows the home page. I am aware of these problems, but they have not been a high priority for me to resolve.

    If WordPress cannot resolve the URL, it should return the error page from the theme (i.e. 404.php in the default theme). Since this is an actual page, it returns the 200 status code rather than the 404 status code, since 404 is page not found, while WordPress is returning a page. I believe this is standard WordPress behavior, independent of the theme or web server (IIS or Apache).

    However, I agree that there are times you would rather have it return a 404 status code. One option could be to figure out when WordPress displays the 404.php page, and just return a 404 status code instead. I don’t know if there would be a plug-in that does this. Let me know if you find out.

  34. Thanks for the reply, Basil. Sorry to hear you haven’t been able to figure this one out yet, either!

    My WordPress installation is actually not even returning the proper 404 page – just what looks like an empty search result for bad pages.

    I’ll let you know if I figure this one out, and if you do sooner, I’d appreciate some info, too. Thanks!

  35. Snakefoot says:

    Also working on creating a Wordpress blog on IIS (Created a plugin which can redirect urls (301) that different than the official or change them to 404).

    Maybe you should consider adding robots.txt to the list of normal contents.

  36. Thanks, Snakefoot, for the information and the plugin.

  37. I’ve been using Snakefoot’s plugin with great success for several weeks now! Thanks again for the great plugin, Snakefoot.

  38. Hi Basil. I’m back again with a new challenge. :)

    Any thoughts on a subscribe to comments plugin that will work with WordPress on IIS? This one (http://txfx.net/code/wordpress/subscribe-to-comments/) doesn’t work. It simply doesn’t send emails. Other email functions on my server work fine from WordPress.

    Do you know of any that will work?

    Thanks in advance for any suggestions.

  39. I checked the Subscribe-To-Comments plugin source, and it sends emails via the WordPress wp_email() function – look for the text “wp_mail($to, $subject, $message, $headers);” in subscribe-to-comments.php

    Looking at the source of the wpPHPMailer plugin, it appears to override the definition of the wp_mail function, so I would think that the Subscribe-To-Comments plugin would work on IIS when combined with the wpPHPMailer plugin.

  40. Thanks, Basil! You’re right! I’ve tested this and confirmed that these two plugins (here’s the mailer – http://www.coffee2code.com/archives/2004/06/28/plugin-wpphpmailer/ ) work in conjunction. Only drawback I see is that the regular email notification to blog author has a blank FROM, but the subscribe to comments plugin works as expected.

    Thanks again!

  41. [...] Check it out! While looking through the blogosphere we stumbled on an interesting post today.Here’s a quick excerptPosted by Basil Vandegriend on January 12th, 2006. Categories: Tools , Web Tags: IIS , WordPress WordPress is the blogging / content management software I use to run this site. WordPress was designed to run under the Apache web server . However, the hosting company for my website uses Microsoft s IIS web server to serve most content, including PHP files which WordPress uses. Setting up WordPress to work under IIS was non-trivial, particularly since existing instructions on the web [...]

  42. Craig says:

    Hi all. I use IIS Mod-Rewrite Pro( http://www.micronovae.com/ModRewrite/ModRewrite.html ) with Wordpress. It accepts .htaccess and clean permalinks work like a charm on IIS.

    Wordpress 2.3 natively supports IIS Mod-Rewrite now, but if you still can’t get the permalinks work correctly, add the following line of code at the beginning of wp-settings.php

    $_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_ORIGINAL_URL'];

  43. IT Training says:

    Looks interesting – I may well check this out further if I decide to go with WordPress on my dedicated box.

  44. [...] Professional Software Development » Running WordPress 2.0 under IIS How to create an ISAPI_Rewrite file for wordpress (tags: wordpress ISAPI_Rewrite) [...]

  45. [...] to Basil Vandegriend? for the solution. Posted by admin Filed in [...]

Leave a Reply

(Not displayed)

« Previous: What is Professional Software Development?    Next: Local Variable Declarations »