IIS, MySQL, WordPress, and The Famous 5-Minute Installation

Yesterday I was upgrading some programs on my home laptop and realized I had an old version of MySQL, 5.1. The current version is 5.6. The 5.1 version of MySQL was installed when I used Microsoft’s Web Platform Installer to install a test WordPress blog. This is a really easy way to checkout software when it works so I set out to upgrade MySQL to the latest version. Surprisingly there is no way to upgrade or remove MySQL using the Web Platform Installer. So I downloaded the community upgrade from www.mysql.com and ran the upgrade. It did not work. I kept getting an unhandled exception error message during the upgrade. Since I did not have any important information in the data base I uninstalled the current version and installed the 5.6 version. Now MySQL is working but I kept getting password errors when I tried to install a new blog using either the Web Platform Installer or Microsoft’s WebMatrix. So I did a complete MySQL reinstall using these instructions for Windows 7 from serverfault.com.

  1. Uninstall MySQL using the uninstaller.
  2. Delete C:\Program Files\MySQL
  3. Delete C:\Program Files (x86)\MySQL
  4. Delete C:\ProgramData\MySQL
  5. Delete from any Users’ AppData folders. Example: C:\Users\rdoverby\AppData\Roaming\MySQL
  6. Reinstall MySQL

This did not fix my problems with Web Platform Installer or WebMatrix. Since I had phpMyAdmin working under IIS and a working version of MySQL, I opted to try “The Famous 5-Minute Installation”. I copied an old WordPress installation to a new folder, followed the instructions, and in about five minutes I had a new WordPress blog working on my laptop.

Problems upgrading Awstats from 6.9 to 7.0

I have a working configuration for Advanced Web Statistics 6.9 (build 1.919).  When I upgraded to the latest release (Advanced Web Statistics 7.0 (build 1.971), it did not work. I ran into this problem in 2009 and backed off.  Now it is time to commit some brain power to fixing the problem.

Problem

When I tried to process a log file no statistical data was being collected. No error messages were generated even though many new records were processed. The data file remained very small.

Analysis

I set up a test environment in which I could process the data with the new version and debugging turned on. To turn debugging on I changed DebugMessages from 0 to 1 in the configuration file and added "-debug=10" parameter to awstats.pl command used to process the log file. This gave me all of the debug messages printed to the screen. I started processing a log file and interrupted it after it had processed a few lines by hitting Ctrl-C. In the debug output I could see that 7.0 version was having problems with the log format. Some values were parsed correctly and others looked like they were offset by one variable. In my configuration I was using a custom logformat which used a combination of IIS column names and AWSTATS keywords. I don’t remember how I created it but I suspect I found an example on the Internet. It worked for the last two years but now it seemed to have a problem with cs-username(%logname).

Solution

My solution was to convert the IIS column names to the corresponding AWSTATS keywords. Even after using the AWSTATS keywords it was still not parsing correctly. To get the parsing to work correctly, I had to change %logname to %other. In my log files, the value for cs-username(%logname) is a single dash.   Obviously it is not important or necessary. When I look at the code, line 9027, I see a comment that says the regular expression code allows spaces to support Lotus Notes. As a result it puts two fields into one variable. Naturally the parsing for %other works correctly. After I knew what the problem and answer was, I could find the answer on the Internet. Here is someone else who experienced the same problem, http://www.internetofficer.com/forum/awstats-iis-installation-and-configuration/awstats-wont-recognize-logname-cs-username-field/. It sure would have been nice if Awstats re-mapped cs-username to %other rather than %logname.

Adding IP Restrictions to IIS 6

A big thanks goes out to the obligatorymoniker and his script for programmatically adding IP restrictions to IIS6. I was looking for a better script to add IP restrictions. My previous script added the restrictions one IP range at a time. This script was adequate for a small number of IP restrictions but recently I was asked to add IP restrictions for every country we do not ship to. We had credit card fraud transaction from one of these countries and the boss was mad. After using Perl and a CIDR to merge the adjacent networks, I still had over 18,000 IP ranges to deny. Using my old script I tried to add these IP ranges to our test system this took over an hour to load. Your script loads the ranges in a couple of seconds.

A big thanks goes out to the obligatorymoniker and his script for programmatically adding IP restrictions to IIS6. I was looking for a better script to add IP restrictions. My previous script added the restrictions one IP range at a time. This script was adequate for a small number of IP restrictions but recently I was asked to add IP restrictions for every country we do not ship to. We had credit card fraud transaction from one of these countries and the boss was mad. After using Perl and a CIDR to merge the adjacent networks, I still had over 18,000 IP ranges to deny. Using my old script I tried to add these IP ranges to our test system this took over an hour to load. Your script loads the ranges in a couple of seconds. Here is how I did this:

  1. I went to http://www.countryipblocks.net/ to get the IP ranges I wanted to block. Beware these ranges include bogon networks(e.g. 192.168.0.0). The first time I applied the IP ranges I blocked myself out.
  2. I used the perl script below to merge the networks.
  3. I used the obligatorymoniker IP Security.vbs script to load the ranges. You will have to change the "IIS://localhost/smtpsvc/1" to the site you want to add the IP restrictions to.
 
use Net::CIDR::Lite;
use NetAddr::IP::Lite;
my $cidr = Net::CIDR::Lite->new;
# Disallow IPs

open (IPDISALLOW, "ip_disallow.txt") || die "couldn't open the file!";

while ($record = <IPDISALLOW>) {
 if (substr($record,0,1) != '#'){
#print $record;
 $cidr->add($record);
 }
}

close(IPDISALLOW);
#print "$_\n" for $cidr->list;
foreach ($cidr->list) {
my $ip = new NetAddr::IP::Lite $_;
#print "The address is ", $ip->addr, " with mask ", $ip->mask, "\n" ;
print $ip->addr, ",", $ip->mask,"$_\n";
} 

w3wp.exe high cpu usage thread

Yesterday I learned an important lesson about IIS logs. They do not show you all of the requests hitting your server! Evidently the log does not show canceled requests.

Over the last couple of days I was receiving complaints about slow responses from our web site. By the time I would look at the CPU utilization it would be within the normal range. I looked in the IIS log file for timeouts but could not find any. So I ran a two hour trace on Thursday afternoon. Friday morning I crunched the trace with PAL and discovered several unaccountable CPU peaks attributable to w3wp.exe. An Internet search for “w3wp.exe high cpu usage”  led me to this thread in which several people recommended using IISPeek to find the misbehaving request. So I installed a trial version of IISPeek and started watching the transactions coming in. Pretty soon I saw something I was not expecting. A shopping site was coming to our site and trying to retrieve a  product advertising feed. What was surprising was not that the shopping site was retrieving the feed but there was no log of it in the IIS log file.   This request had been consuming our CPU for several minutes and then disappearing without a trace. I knew this query had some serious performance issues but the IIS log indicated that it had been working on previous days. I did not know it was running so often. With IISPeek and Task Manager running together I could see the impact on the site. Evidently this particular shopping site would time out or cancel the query before our site either returned the data or timed out.  It was at this moment that I figured out that IIS must have a “no harm, no foul” policy about canceled queries. My reliance on the IIS log was a mistake in this case. Since this shopping site was not getting the data, the shopping site would try again at a later time. When I was watching it with IISPeek I was seeing this request about every fifteen minutes. Fortunately I had already developed some web page caching code I could implement quickly and get us over this hump. Within an hour the shopping site had its data and our web site was back to normal. I have solved a lot of web site problems by looking at the IIS log but in this case it was not the right tool for the job. On Monday I am buying a copy of IISPeek!

Top free tools for Windows server administration

Every so often you find a tool you have never heard of.  This week the tool that caught my attention was  Performance Analysis of Logs (PAL). It was recommended by Bruce Mackenzie-Low in a newsletter from SearchWindowsServer.com and it looks it will be helpful with the “art” of performance analysis. I played with it a little bit using the IIS and SQL templates. It seemed to provide some helpful insight into potential performance issues. My aim is to analyze our web server for IIS and database bottlenecks.