Category Archives: Systems Administration

Setting up multiple versions of IE plus cookies

The web has got the whole ‘multiple versions of IE’ fairly well documented already, but you have to scroll way down to the bottom of the second article to see that if you want cookies to work, you’ll have to download wininet.dll from Microsoft.

So the full directions:

  1. Download IE 5.0 or IE 5.5
  2. Use a zip utility to unpack either / both of the above zip files.
  3. Download wininet.dll from microsoft.com.
  4. Use a zip utility to unpack the .exe file that you downloaded in step 3.
  5. Copy the resulting Wininet.dll from step 4 to the location that you unzipped the IE files in step 2.
  6. Start up IE and go!

Using a HOSTS file on OS X

In the Windows world it’s a reasonably straightforward process to add pseudo domain names using the HOSTS file usually located in c:\windows\system32\drivers\etc\. Open the file, add a name / IP address entry, save the changes and you’re off and running. It’s slightly more involved on OS X as this site details. OS X uses lookupd to do name resolution and by default (at least on my machine) it is configured to look to a DNS server before referencing the local HOSTS file, which is not how Windows works. Turns out it’s reasonably easy to change (as detailed on the macwrite.com link mentioned above):

cd /etc
sudo mkdir lookupd
cd lookupd
ls
cp hosts hosts.original
sudo echo LookupOrder Cache FF NI DNS DS > hosts
sudo kill -HUP 'cat /var/run/lookupd.pid'

After that’s done, you can add / delete / modify domain name to IP address mappings using the NetInfo Manager tool.

ASP, ServerVariables, Server_Name, Windows 2003, IIS6

We’re in the process of upgrading our webservers to Windows 2003 and thus IIS6. One of the issues we ran into was that the Server_Name key of the ServerVariables collection in VBScript started returning the computer name of the machine rather than the host name of the website. I spent a couple hours googling and found nothing, my recent hire found the hot fix on microsoft.com in about 5 minutes today (which shows how important good google skills are). In short, there’s a security issue with IIS (surprised?) whereby sending a GET request to an IIS web server without sending a host header would result in the web server returning the IP address of the web server in the content location field of the response TCP header. The easy fix is to run:

cscript adsutil.vbs set w3svc/UseHostName false

which modifies all IIS web sites to return the website host name rather than the machine name / IP address when getting the Server_Name key of the ServerVariables collection.

Subversion + Ant Release Scripts

I’m not sure where this script fits into ‘The Joel Test’, but in the interest of automating the process of releasing a build in Subversion, I had the new guy (hey Pete!) spend his first couple days writing a script that:

  1. copies the trunk to the named branch (ie: /myproject/trunk –> /branches/1.10)
  2. copies the ‘latest’ tag to a tag called ‘rollback’
  3. copies the newly created branch to /tags/latest

The end result is that when we decide to do a release to the production environment, we can simply run the script (download the plain text) which copies the Subversion trunk (the main line of development for those unfamiliar with Subversion) to a tag we called ‘latest’ and also to a branch which matches the version number of the release. We point our production servers to /$project/tags/latest and our development servers (which we setup to run nightly builds) to /$project/trunk.

And just so we know that everything is running smoothly, he modified the Ant deployment script so that it sends an email upon completion indicating success or failure along with the output from the build. The email part I thought was going to be relatively simple (ie: use the mail task), but I wasn’t so sure about the generated output. Turns out that you can use MailLogger feature to listen for and get the status of build events simply by appending a logger flag to the invocation of ant:

ant -logger org.apache.tools.ant.listener.MailLogger

and then by setting the appropriate properties in your build file.

ASP.NET: The resource cannot be found.

Spent some time today buried in IIS trying to figure out why an ASP.NET application would throw the following error message for every single page that existed in an application within a website:

Server Error in ‘/myapp’ Application.
—————————————————-
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested Url: /myapp/default.aspx
—————————————————-
Version Information: Microsoft .NET Framework Version:1.1.4322.2032; ASP.NET Version:1.1.4322.2032

Googled for “resource cannot be found” and found this link on the third result page. In it Jarrett mentions that he solved the problem by reading this experts-exchange.com question which suggests setting up the application as a Virtual Directory in IIS instead of simply marking the folder in the website as an application, which of course solved the problem for me as well. Since a picture is worth a thousand words, here’s the difference between a Virtual Directory (which is an application in and of itself) and directory in IIS that has been marked as an application:

virtual_directory.gif

directory.gif

My suspicion is that the problem has to do with ASP.NET configuration inheritance settings with Virtual Directories not inheriting from parent directories like a folder marked as an application would, but there isn’t much to go on. Any Microsoft IIS experts out there want to talk about the difference between a Virtual Directory and a folder that has been marked as an application from a configuration standpoint?

Trailing Slashes, IIS and F5 / Big-IP

We’ve had a problem on our websites at work for the last couple years where if a user doesn’t use a trailing slash when visiting a directory, ie:

http://www.hostname.com/mydirectory

the user gets a “The page cannot be displayed” error. The problem is that if you don’t use a trailing slash IIS sends a redirection to use the trailing slash:

REQUEST
---------------------
GET /mydirectory HTTP/1.1
Host: hostname.com


RESPONSE
---------------------
HTTP/1.x 302 Object Moved
Location: http://hostname.com:xxx/mydirectory/

Notice that the redirect includes the port designation? We run multiple websites on a single box and (for reasons beyond me) we don't use host headers so we have to use non standard ports in IIS. In the case above the web server thinks it's running the site on port xxx, which it technically is, but the world doesn't see that, nor can it use that port to access the site. At the time I thought it was the F5 that was redirecting users inappropriately, but there was nothing on the F5 website to back that up. There is now: How do I stop redirects from the web server behind BIG-IP?

In short, any website (IIS or Apache) running behind the F5 / Big-IP that is not using port 80 will show this behavior, there are a couple fixes:

a) use an IIS ISAPI filter (or mod_rewrite on Apache) to rewrite the redirects

b) use an F5 / Big-IP port redirect rule

c) use an F5 / Big-IP trailing slash redirect rule

If you read the tech note you'll see that Option 'b' will result in 2 redirects (client requests hostname.com/mydirectory --> IIS redirects to hostname.com:xxx/mydirectory/ --> Big-IP redirects to hostname.com/mydirectory/) and also lets any technical users know which port we're running on websites. Option 'c' is mentioned in the tech note as being the last gasp: "F5 Networks recommends using this rule only if there is no other alternative" so I chose option 'a'. There is a free ISAPI rewrite engine called (conveniently) ISAPI_Rewrite from helicontech.com. I installed it and then added the appropriate rewrite rule:

RewriteCond Host: (.*)
RewriteRule ([^.?]+[^.?/]) http\://$1$2/ [I,R]

and everything works again. Balance has been restored to the world.

AWStats Installation Notes

I tried installing AWStats a couple months ago on my server, got frustrated after an hour or two of reading the documentation and trying to figure out permissions problems, gave up and then tried again about two weeks ago, this time with more patience. Maybe after reading my notes (on RedHat Linux) someone else won’t have to exercise as much patience.

First step: download AWStats, unzip (I unpacked to /usr/local/awstats/) and then execute the following script to start the setup process:

perl awstats_configure.pl

After you complete that step, you’ll have a couple AWStats directives in your Apache configuration. Since some of the sites I’ve written use servlet filters to do URL rewriting and because I wanted to minimize the number of AWStats entry points (AWStats was recently hacked), I setup a virtual host in Apache as a reporting domain. I then moved the AWStats directives inside this reporting virtual domain.

Next, using the sample awstats.mysite.com.conf, you’ll need to create the a domain configuration file for every site that you want to report on and place each one in /etc/awstats/ (read more about the domain configuration files here, scroll down to step #4 and #5). So I ended up with something like:

# ls /etc/awstats
awstats.cephas.net.conf
awstats.blackberryblog.com.conf
...

After you’ve got all your configuration files setup, you’ll want to run awstats against all your old log files (assuming that you’ve got old log files that you want to process). There’s no easy way of getting all your old log files processed, I had to modify the configuration file to point to the zipped up log file:

LogFile="gzip -d </usr/hosts/yoursite.com/logs/200205.zip | "

run awstats:

perl awstats.pl -config=yoursite.com -update

and then modify the configuration file to point to the next month. If I was better at shell scripting I’m sure I could have worked out some way of automating this, but I didn’t have that many log files laying around so it wasn’t a big deal. After you’ve processed all your old log files, you’ll want to point AWStats to look at your current log files. I configured my machine so that it always processes the log file based on yesterday’s date, so my configuration looked like this:

LogFile="/usr/hosts/yoursite.com/logs/%YYYY-24%MM-24.log"

and then I setup a cron job to execute AWStats every night by saving this snippet of code as a script and placing it in your /etc/cron.daily/ folder (cron.daily runs based on the settings in /etc/crontab)

#!/bin/bash
cd /usr/local/awstats/tools
perl awstats_updateall.pl now

So now you’ve got your configuration files, you’ve got a script that processes your logs automatically every night and you want to view the reports from a web browser. So you point your web browser to:

http://reporting.yoursite.com/awstats/awstats.pl?config=yoursite.com

and if you’re like me at this point you’ll run into an error message that makes no sense at all:

[Fri Jun 03 15:52:42 2005] [crit] [client xxx.xxx.xxx.xxx] (13)Permission denied: /usr/local/awstats/.htaccess pcfg_openfile: unable to check htaccess file, ensure it is readable

The funny thing was that I didn’t have an htaccess file anywhere near the awstats configuration, this error message drove me batty. After googling for an exceptionally long period of time, I updated both /var/lib/awstats/ and /usr/local/awstats/ so that the Apache user owned them.

chown apache.apache /var/lib/awstats
chown apache.apache /usr/local/awstats

Finally, unless you want everyone to see your stats (and allow anyone to access the AWStats.pl script), you’ll want to lock down the cgi-bin directory so that only valid users can access your system. Create a .htaccess and a .htpasswd file in your /usr/local/awstats/wwwroot/cgi-bin/ directory (making to sure to set AllowOverride All in your directive inside the VirtualHost in apache). Configure your .htaccess to only allow access to valid-user:

AuthName "reporting"
AuthType Basic
AuthUserFile /usr/local/awstats/wwwroot/cgi-bin/.htpasswd
Require valid-user

You can create the .htpasswd file by running this command:

htpasswd -c $filename $username

and then add users:

htpasswd $filename $username

and make sure to modify your AWStats configuration file to allow access to __REMOTE_USER__ or the specific user that you want to grant access to that file.

You should now have a working, secure and fully automated AWStats reporting system! Congratulations!

Delicious + Movable Type + Java

I’ve been keeping a list of interesting links in a text file for the last couple years and only recently thought better of it and started using del.icio.us to store links. And I wanted to show the links as part of this blog, but I wasn’t satisfied with just including their RSS feed of my links in blog (what happens when / if del.icio.us disappears?) so I whipped up a some code using the delicious-java library and the Apache XML-RPC library that extracts my delicious links from the previous day and then posts them directly my Movable Type blog using the XML-RPC API that comes standard with Movable Type. After putting it up on my server, I wrote a simple shell script that invokes the Java class and then popped that into /etc/cron.daily/ so that it will get called a nightly basis, voila!

#!/bin/bash
cd /usr/apps/delicious/
java -cp commons-codec-1.3.jar:commons-httpclient-3.0-rc2.jar:
commons-logging-1.0.4.jar:delicious-1.6.jar:xmlrpc-1.2-b1.jar:bin net.cephas.blog.DeliciousPoster config.properties

If you’d like to run it your own server, feel free to download the binaries (which include the source code), edit config.properties to match your Movable Type and de.licio.us profiles and scheduled it to run on a nightly basis.