Scott Forsyth's Blog

Postings on IIS, ASP.NET, SQL Server, Webfarms and general system admin.
Troubleshoot ASP.NET Errors Remotely–while Appearing Local

For years I’ve wanted to be able to troubleshoot website remotely by seeing the detailed error report, while ensuring that other users on the web only see the friendly non-detailed error.

This is now possible with URL Rewrite 2.0. Through a simple rule, you can make it appear to ASP.NET that you are testing from the local server, without opening it up to the rest of the world.  You can do this by using URL Rewrite to change the REMOTE_ADDR server variable, essentially fooling ASP.NET into thinking that you are testing locally.

However, there is one gotcha.  If you are on a shared or corporate server, you will need your host or admin department to approve one setting that is likely not enabled for you, or exposed in their control panel.  That will prevent some users from being able to apply this.  Keep reading for more details on that.

Before

image

After

image

After the following changes, you, and only you, will be able to see the detailed error message when testing remotely.

What are Custom Errors

Custom Errors allow you to hide the real error from your visitors.  You don’t want to expose sensitive information about your website.  The detailed errors can show a few lines of code, which could be sensitive information, for example, your connection string to your database.

The custom error page can be Microsoft’s default error page, or it can be one that you create and pretty up to match the rest of your website.

The ASP.NET <customErrors /> mode property has 3 possible values.  They are Off, On and RemoteOnly

In brief, here is what they mean:

Off Show everyone the detailed error message.  This is rarely a good idea.
On Don’t show anyone the detailed error message. 
RemoteOnly Only show the detailed error message if you are testing from the local server where the site resides.

If you have access to the server, you can use RemoteOnly which allows you to test without opening up your errors to the world. 

However, you may not always have local access, or you may run into an issue that only occurs from certain computers or browsers.

If you are like me, you have done troubleshooting in the past where you’ve temporarily changed the mode to Off, reproduce the error, then changed the mode back again.

Of course there are other options for debugging your application, but the detailed errors page is one of the easiest first steps to troubleshooting an issue.

Three Steps to Secure Remote Troubleshooting

There are 3 steps to leverage RemoteOnly from a remote location.

  1. Set RemoteOnly for customErrors
  2. Have server administrator approve server variable REMOTE_ADDR
  3. Create URL Rewrite rule

Let’s look at them one at a time.

1) Set RemoteOnly for customErrors

You’re probably well familiar with ASP.NET customErrors so I’ll just summarize.

In the <system.web> section of your web.config file, add the following:

<customErrors mode="RemoteOnly" />

Or, feel free to add your own custom errors.  Here’s a link with documentation on how to do that.

2) Have Server Administrator Approve Server Variable REMOTE_ADDR

For this functionality to work, you will need to have the server administrator approve REMOTE_ADDR as a server variable that can be overwritten.  I can’t think of a security reason why it shouldn’t be changed, unless you have a custom application that depends on knowing the remote address, and you don’t trust the site owner.  So, if you ask nicely, you can hopefully get this changed.

To approve REMOTE_ADDR, from IIS Manager, they will need to select the website and open up URL Rewrite.  Go to View Server Variables from the Actions pane.

image

Add a Server Variable called REMOTE_ADDR

image

3) Create URL Rewrite rule

Finally, you need to create a rule that can tell that it’s you visiting, and changes REMOTE_ADDR to 127.0.0.1 to make you appear local.

There are multiple ways to tell if it’s you.  One is by IP address.  This is probably the easiest in most cases, but be careful if you have a dynamic IP, that it could change over time and expose your detailed errors to someone else. 

Another option is to check by querystring, so if you ever want to see the error, just add ?ShowMeDetailedErrors=true to the URL. 

If you want to get adventurous, you could write a cookie with another page, and use cookies to authenticate yourself.  URL Rewrite has access to the non-encrypted cookie.

For this example, I’ll show how to do it based on your IP address.

First, find out what your IP is.  Use www.whatsmyip.org or whatever method you prefer.  Note that if you’re using a VPN (like I often am), than your network may see a different IP than whatsmyip.org sees.  To be absolutely sure what IP your server sees, you could write a script to show all server variables as I blogged about here.

To create the Rewrite rule from IIS Manager, go to URL Rewrite for your website (or folder) and add a new blank rule.

Give it a friendly name like “Appear as Local” and set the Pattern to “.*”.

image

Create a condition for your IP address.  Set the condition to {REMOTE_ADDR} and the pattern to your IP address.  You can enter the IP address directly, like 69.132.61.123, or to  be more accurate, the proper regex is 69\.132\.61\.123.  The . (dot) is a wildcard in regex which is why either method works.

image

Now here’s where the trickery comes in.  Rewrite the REMOTE_ADDR Server Variable to 127.0.0.1 by adding a rule to set REMOTE_ADDR to 127.0.0.1.

image

Finally set the Action to None since you don’t want to do anything else besides the Server Variables rewrite.

It’s worth noting that the IIS Logs use REMOTE_HOST rather than REMOTE_ADDR, so this change won’t affect the IIS logs.  The logs will still see your real IP address.

The rule that is created will look something like this:

<rule name="Appear as Local">
<match url=".*" />
<serverVariables>
<set name="REMOTE_ADDR" value="127.0.0.1" />
</serverVariables>
<action type="None" />
<conditions>
<add input="{REMOTE_ADDR}" pattern="69\.132\.61\.123" />
</conditions>
</rule>

If you want to allow multiple IP addresses, then use the pipe (|), which means OR in RegEx, like so: “69.132.61.123|69.132.61.124|192.168.1.110|10.0.5.5”. 

Pretty clean and simple really.  Now remote troubleshooting of your site has gotten easier without exposing the detailed errors to the rest of the world!

Configuring IIS6 for WebMatrix

The news of WebMatrix was just released, causing a lot of interest in the tech community.  See Scott Guthrie’s blog post for details on WebMatrix, IIS Express, SQL Server Compact and the Razor syntax.

The nice thing about all of these technologies is that they use managed code and are xcopyable, even to a web host that isn’t fully prepared for it.  Even the SQL Server CE engine is xcopyable.  However, at Orcsweb, we’ve been working hard to make the deployment story for WebMatrix extra easy under the name of Cytanium, an Orcsweb venture.  We offer free accounts for testing WebMatrix publishing.

I had someone ask me today about setting up their site on an IIS6 server.  Turns out that it’s very straight forward.  I haven’t tested a lot of scenarios yet to see if there are other settings that I missed, but so far everything looks good.

Configuring IIS 6.0 for WebMatrix and MVC

WebMatrix uses .cshtml and .vbhtml as the file extensions, it is also uses the new extensionless routing engine, plus many of the current apps that you’ll find in the Web Platform Installer (WebPI) use MVC or other extensionless methods.  Therefore, the easy solution is to add ASP.NET as the wildcard handler.

Note that if you add a wildcard handler, default docs won’t work for traditional webforms apps unless you specifically handle them.  So, just add wildcard handlers to your WebMatrix folders.

To add a wildcard handler, fire up IIS Manager, navigate to the folder that you want to add the wildcard mapping, right-click and click Properties.

Then you need to get the path to the framework version.  My favorite way to do that is to pick an existing extension, like .asax (right up at the top) and edit it.  Copy the path from the “Executable” field into your clipboard.  It will be something like this:

.NET 2 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll
.NET 2 x64 C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll
.NET 4 C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll
.NET 4 x64 C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll

Cancel out of that dialog box once you have the path in your clipboard.

In the Wildcard section of the Application Configuration, insert the extension and uncheck the “Verify that file exists” checkbox.

image

Save out.  That’s it!

Everything else will be the same as with IIS 7.x.  The next challenges to watch for that that may come up will likely be related to the framework version, whether everything was correctly deployed, database connection strings, and whether sites in subfolders are marked as applications. 

Hope you enjoy the WebMatrix testing and deployments!

Posted: Jul 08 2010, 07:42 PM by OWScott | with 3 comment(s)
Filed under: ,
Visual Studio IntelliSense for URL Rewrite

Visual Studio doesn’t have IntelliSense support for URL Rewrite by default.  This isn’t a show stopper since it doesn’t result in stop errors. However, it’s nice to have full IntelliSense support and to get rid of the warnings for URL Rewrite rules.

RuslanY has released a Visual Studio schema update for URL Rewrite 2.0 which is available as a free quick download.  The installation instructions (they are quick and easy) can be found here, which also include the schema for URL Rewrite 1.1.  

The install takes effect immediately without restarting Visual Studio.

A side question commonly comes up.  Can you get URL Rewrite support for Visual Studio Web Server (aka Cassini).  The answer is no.  To get URL Rewrite support in your development environment, use IIS7.  You can set your Visual Studio projects to use IIS7 though, so you can have full debug, F5 or Ctrl-F5 support for IIS.

URL Rewrite – Multiple domains under one site. Part II

I believe I have it …

I’ve been meaning to put together the ultimate outgoing rule for hosting multiple domains under one site.  I finally sat down this week and setup a few test cases, and created one rule to rule them all. 

In Part I of this two part series, I covered the incoming rule necessary to host a site in a subfolder of a website, while making it appear as if it’s in the root of the site.  Part II won’t work without applying Part I first, so if you haven’t read it, I encourage you to read it now.

However, the incoming rule by itself doesn’t address everything.  Here’s the problem …

Let’s say that we host www.site2.com in a subfolder called site2, off of masterdomain.com.  This is the same example I used in Part I.

 

Using an incoming rewrite rule, we are able to make a request to www.site2.com even though the site is really in the /site2 folder. 

The gotcha comes with any type of path that ASP.NET generates (I’m sure other scripting technologies could do the same too).  ASP.NET thinks that the path to the root of the site is /site2, but the URL is /.  See the issue?  If ASP.NET generates a path or a redirect for us, it will always add /site2 to the URL.  That results in a path that looks something like www.site2.com/site2

In Part I, I mentioned that you should add a condition where “{PATH_INFO} ‘does not match’ /site2”.  That allows www.site2.com/site2 and www.site2.com to both function the same.  This allows the site to always work, but if you want to hide /site2 in the URL, you need to take it one step further.

One way to address this is in your code.  Ultimately this is the best bet.  Ruslan Yakushev has a great article on a few considerations that you can address in code.  I recommend giving that serious consideration.  Additionally, if you have upgraded to ASP.NET 3.5 SP1 or greater, it takes care of some of the references automatically for you.

However, what if you inherit an existing application?  Or you can’t easily go through your existing site and make the code changes?  If this applies to you, read on.

That’s where URL Rewrite 2.0 comes in.  With URL Rewrite 2.0, you can create an outgoing rule that will remove the /site2 before the page is sent back to the user.  This means that you can take an existing application, host it in a subfolder of your site, and ensure that the URL never reveals that it’s in a subfolder.

Performance Considerations

Performance overhead is something to be mindful of.  These outbound rules aren’t simply changing the server variables.  The first rule I’ll cover below needs to parse the HTML body and pull out the path (i.e. /site2) on the way through.  This will add overhead, possibly significant if you have large pages and a busy site.  In other words, your mileage may vary and you may need to test to see the impact that these rules have.  Don’t worry too much though.  For many sites, the performance impact is negligible.

So, how do we do it?

Creating the Outgoing Rule

There are really two things to keep in mind. 

First, ASP.NET applications frequently generate a URL that adds the /site2 back into the URL.  In addition to URLs, they can be in form elements, img elements and the like.  The goal is to find all of those situations and rewrite it on the way out.  Let’s call this the ‘URL problem’.

Second, and similarly, ASP.NET can send a LOCATION redirect that causes a redirect back to another page.  Again, ASP.NET isn’t aware of the different URL and it will add the /site2 to the redirect.  Form Authentication is a good example on when this occurs.  Try to password protect a site running from a subfolder using forms auth and you’ll quickly find that the URL becomes www.site2.com/site2 again.  Let’s term this the ‘redirect problem’.

Solving the URL Problem – Outgoing Rule #1

Let’s create a rule that removes the /site2 from any URL.  We want to remove it from relative URLs like /site2/something, or absolute URLs like http://www.site2.com/site2/something.  Most URLs that ASP.NET creates will be relative URLs, but I figure that there may be some applications that piece together a full URL, so we might as well expect that situation.

Let’s get started.  First, create a new outbound rule.  You can create the rule within the /site2 folder which will reduce the performance impact of the rule.  Just a reminder that incoming rules for this situation won’t work in a subfolder … but outgoing rules will.

image

Give it a name that makes sense to you, for example “Outgoing – URL paths”.

Precondition.  If you place the rule in the subfolder, it will only run for that site and folder, so there isn’t need for a precondition.  Run it for all requests.  If you place it in the root of the site, you may want to create a precondition for HTTP_HOST = ^(www\.)?site2\.com$.

For the Match section, there are a few things to consider.  For performance reasons, it’s best to match the least amount of elements that you need to accomplish the task.  For my test cases, I just needed to rewrite the <a /> tag, but you may need to rewrite any number of HTML elements.  Note that as long as you have the exclude /site2 rule in your incoming rule as I described in Part I, some elements that don’t show their URL—like your images—will work without removing the /site2 from them.  That reduces the processing needed for this rule.

Leave the “matching scope” at “Response” and choose the elements that you want to change.

image

Set the pattern to “^(?:site2|(.*//[_a-zA-Z0-9-\.]*)?/site2)(.*)”.  Make sure to replace ‘site2’ with your subfolder name in both places.  Yes, I realize this is a pretty messy looking rule, but it handles a few situations.  This rule will handle the following situations correctly:

Original Rewritten using {R:1}{R:2}
http://www.site2.com/site2/default.aspx http://www.site2.com/default.aspx
http://www.site2.com/folder1/site2/default.aspx Won’t rewrite since it’s a sub-sub folder
/site2/default.aspx /default.aspx
site2/default.aspx /default.aspx
/folder1/site2/default.aspx Won’t rewrite since it’s a sub-sub folder.

For the conditions section, you can leave that be.

Finally, for the rule, set the Action Type to “Rewrite” and set the Value to “{R:1}{R:2}”.  The {R:1} and {R:2} are back references to the sections within parentheses.  In other words, in http://domain.com/site2/something, {R:1} will be http://domain.com and {R:2} will be /something.

image

If you view your rule from your web.config file (or applicationHost.config if it’s a global rule), it should look like this:

<rule name="Outgoing - URL paths" enabled="true">
    <match filterByTags="A" pattern="^(?:site2|(.*//[_a-zA-Z0-9-\.]*)?/site2)(.*)" />
    <action type="Rewrite" value="{R:1}{R:2}" />
</rule>

Solving the Redirect Problem

Outgoing Rule #2

The second issue that we can run into is with a client-side redirect.  This is triggered by a LOCATION response header that is sent to the client.  Forms authentication is a common example.  To reproduce this, password protect your subfolder and watch how it redirects and adds the subfolder path back in.

Notice in my test case the extra paths:

http://site2.com/site2/login.aspx?ReturnUrl=%2fsite2%2fdefault.aspx

I want to remove /site2 from both the URL and the ReturnUrl querystring value.  For semi-readability, let’s do this in 2 separate rules, one for the URL and one for the querystring.

Create a second rule.  As with the previous rule, it can be created in the /site2 subfolder.  In the URL Rewrite wizard, select Outbound rules –> “Blank Rule”.

Fill in the following information:

Name response_location URL
Precondition Don’t set
Match: Matching Scope Server Variable
Match: Variable Name RESPONSE_LOCATION
Match: Pattern ^(?:site2|(.*//[_a-zA-Z0-9-\.]*)?/site2)(.*)
Conditions Don’t set
Action Type Rewrite
Action Properties {R:1}{R:2}

It should end up like so:

<rule name="response_location URL">
    <match serverVariable="RESPONSE_LOCATION" pattern="^(?:site2|(.*//[_a-zA-Z0-9-\.]*)?/site2)(.*)" />
    <action type="Rewrite" value="{R:1}{R:2}" />
</rule>

Outgoing Rule #3

Outgoing Rule #2 only takes care of the URL path, and not the querystring path.  Let’s create one final rule to take care of the path in the querystring to ensure that ReturnUrl=%2fsite2%2fdefault.aspx gets rewritten to ReturnUrl=%2fdefault.aspx.

The %2f is the HTML encoding for forward slash (/).

Create a rule like the previous one, but with the following settings:

Name response_location querystring
Precondition Don’t set
Match: Matching Scope Server Variable
Match: Variable Name RESPONSE_LOCATION
Match: Pattern (.*)%2fsite2(.*)
Conditions Don’t set
Action Type Rewrite
Action Properties {R:1}{R:2}

The config should look like this:

<rule name="response_location querystring">
    <match serverVariable="RESPONSE_LOCATION" pattern="(.*)%2fsite2(.*)" />
    <action type="Rewrite" value="{R:1}{R:2}" />
</rule>

It’s possible to squeeze the last two rules into one, but it gets kind of confusing so I felt that it’s better to show it as two separate rules.

Summary

With the rules covered in these two parts, we’re able to have a site in a subfolder and make it appear as if it’s in the root of the site.  Not only that, we can overcome automatic redirecting that is caused by ASP.NET, other scripting technologies, and especially existing applications.

Following is an example of the incoming and outgoing rules necessary for a site called www.site2.com hosted in a subfolder called /site2.  Remember that the outgoing rules can be placed in the /site2 folder instead of the in the root of the site.

<rewrite>
    <rules>
        <rule name="site2.com in a subfolder" enabled="true" stopProcessing="true">
            <match url=".*" />
            <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                <add input="{HTTP_HOST}" pattern="^(www\.)?site2\.com$" />
                <add input="{PATH_INFO}" pattern="^/site2($|/)" negate="true" />
            </conditions>
            <action type="Rewrite" url="/site2/{R:0}" />
        </rule>
    </rules>
    <outboundRules>
        <rule name="Outgoing - URL paths" enabled="true">
            <match filterByTags="A" pattern="^(?:site2|(.*//[_a-zA-Z0-9-\.]*)?/site2)(.*)" />
            <action type="Rewrite" value="{R:1}{R:2}" />
        </rule>
        <rule name="response_location URL">
            <match serverVariable="RESPONSE_LOCATION" pattern="^(?:site2|(.*//[_a-zA-Z0-9-\.]*)?/site2)(.*)" />
            <action type="Rewrite" value="{R:1}{R:2}" />
        </rule>
        <rule name="response_location querystring">
            <match serverVariable="RESPONSE_LOCATION" pattern="(.*)%2fsite2(.*)" />
            <action type="Rewrite" value="{R:1}{R:2}" />
        </rule>
    </outboundRules>
</rewrite>

If you run into any situations that aren’t caught by these rules, please let me know so I can update this to be as complete as possible.

Happy URL Rewriting!

Posted: May 26 2010, 07:37 PM by OWScott | with 43 comment(s) |
Filed under: , , ,
Managed Service Accounts (MSA) and Virtual Accounts

Windows Server 2008 R2 and Windows 7 have two new types of service accounts called Manage Service Accounts (MSA) and Virtual Accounts.  These make long term management of service account users, passwords and SPNs much easier.

Consider the environment at OrcsWeb.  As a PCI Compliant hosting company, we need to change all security related passwords every 3 months.  This is a substantial undertaking each time because of hundreds of passwords spread throughout our enterprise.  We have scripts and tools and manual steps, causing us to groan each time we get our password change reminder at the beginning of the new quarter.  Even non-PCI compliant companies have the need to manage passwords for service accounts.

Now, imagine if the effort of changing passwords on each of the service accounts was completely eliminated, without any security risk!  That’s what Managed Service Accounts allows (too bad service accounts weren’t the only type of password that we have to manage).

Essentially, Active Directory takes care of the password and SPN management for us, allowing us to create accounts, assign them to a Windows Service, and never require us to update the password again.

Hello World

I find that getting the first ‘hello world’ working is oftentimes the most difficult, so in this blog I want to cover an end-to-end walkthrough of a simple configuration.

A more detailed walkthrough can be found in the Service Accounts Step-by-Step Guide.  However, I hope to present an easier walkthrough for getting started.

Environment

My environment is made up of 2 virtual machines from Vaasnet. I promoted one to become a domain controller and the other to join the new domain.  Both machines are Windows Server 2008 R2.

Windows 7 is also supported as a member computer, and you can run this with a Windows Server 2008 or 2003 Domain by installing the Active Directory Management Gateway Service and running adprep /domainprep.  See the Step-by-Step Guide for more details about that.

Pre-requisites (for a pure Windows Server 2008 R2 environment)

The domain server will have everything necessary.  PowerShell 2.0 is installed with R2 by default and the management tools are already installed.

The member server or computer will need to have the Active Directory PowerShell Snap-in enabled. 

To do this from Windows Server 2008 R2, perform the following:

  • Open Server Manager
  • Click “Features and Add Feature”

image

  • Add the “Active Directory module for Windows PowerShell” in /Remote Server Administration Tools/AD DS and AD LDS Tools.

image

  • Click Next / Install.

Adding a Managed Service Account

A Managed Service Account can be assigned to only 1 computer.  First you need to create the account, then assign it to a server.  There are multiple ways to do this, but I’ll show the easiest way that worked well for me.

On either the domain computer or member computer:

  • Open PowerShell
  • Type the following, where “TestService” is the name of the new service account.
Import-Module ActiveDirectory
New-AdServiceAccount -name TestService

Note: You need to Import-Module ActiveDirectory each time you start PowerShell, unless you add it as a permanent reference in PowerShell.

This will create a new Managed Service Account in Active Directory under the “Managed Service Accounts” section.

image

If you edit the properties of the account, you’ll see that it’s full of lots of configuration options (joking!  See following image).

image

If you want to get further information, you can use PowerShell.  Review the details with

Get-AdServiceAccount –identity “TestService”

image

Now that we’ve created the account, we need to assign it to the computer.  Remember that it can only be assigned to 1 computer at a time.  From the computer that you want to assign it to, type the following: (Don’t forget to type Import-Module ActiveDirectory if you haven’t yet on this computer)

Install-AdServiceAccount -identity "TestService"

For creating and assigning the user, that’s it!

Assigning to a Windows Service

Now that we’ve created the account and assigned it to a computer, we need to add it to a Windows Service.  It’s kind of obvious in the name, but it’s worth mentioning that these are managed service accounts, and can only be used for Windows Services.  You can’t log into a server with them or use them for non-service purposes.  This makes sense since we don’t know what the password is.

Unlike the other new account, called Virtual Accounts, MSA’s can be discovered from the Find User tools in Windows.  To assign the user, first open up the Windows Services snap-in (services.msc).  Find your service and edit the properties.

In the Log On tab, enter your new service account.  There are a couple tricks here.

  • The service name has a $ at the end of it.  So for my test domain called scott.int, my user account is scott.int\TestService$
  • Password: You don’t know what the password is?  No problem!  Make up something, or leave it blank.  Just make sure that the confirm password matches.  What you enter won’t be saved so it’s no less secure if you leave it blank.
  • If you want to browse to find the new user
    • click Browse…
    • ensure that the location section is set to your domain and not the local machine
    • For the Object Types, edit and ensure that “Service Accounts” are selected.

service accounts

    • Now you can go ahead and search as you would normally search for a user account.

find now

Permissions

As with any Windows user account, you must assign necessary permissions to disk.  Usually the service itself needs at least read permissions, and if the service needs access to anything else on disk or in the registry, you must grant the new account the appropriate permissions.

I wanted to confirm what access is needed across the network.  Since this account can only be assigned to a single computer, I wanted to make sure that network resources saw the network call as coming from this account and not from the computer account.  The reason I was worried about that is because all of the documentation I could find mentioned that the Virtual Accounts run as the Computer Account.  I wanted to make sure that the Managed Service Account wasn’t the same.

To test, I created a Windows Service called NetworkCall which writes a test file to a path set in App.Config.  This allowed me to point to a local path or a network path and ensure that the permissions worked as I expected.

This test erased my concerns and confirmed that network access is made using this account.  Without the TestService$ account, my test service wouldn’t start.  Once I added TestService$ with Modify permissions (I added it to the Windows Share permissions too) then the service started and the file was written successfully.

image

Just for spite, I removed the TestService$ account and added the Computername$ account.  It didn’t work.  So, this confirms that Managed Service Accounts use the MSA account only. 

Virtual Accounts

The 2nd type of service account is the Virtual Account.  I won’t spend too much time here because it’s so straight forward that I can walk through a demo easily.

Basically with Virtual Account, they already virtually exist.  They are used by IIS7, and can be used for Windows Services.  The only gotcha with Virtual Accounts is that if you need to access network resources, you do so as the computer account.  This means that you must grant the entire computer access to a network resource, which, in my opinion, should rarely be done.

However, for services that only access local resources, virtual accounts are great!

All you need to do is assign an account with the name NT SERVICE\{servicename}.  For example, “NT SERVICE\NetworkCall”.  Leave the password blank or bogus.  That’s it! The account is already there.  You don’t need to create it or turn it on or anything.  As long as you’re using Windows Server 2008 R2 or Windows 7, you’re done.

For network calls, access needs to be granted to Computername$ as shown in the following screenshot.  Remember that I don’t recommend doing this for network access.  If you need to make network calls, use a MSA instead of Virtual Account.

image

IIS and Virtual Accounts

For IIS and Virtual Accounts, the user is called “IIS AppPool\{apppoolname}”.  For example, “IIS AppPool\DefaultAppPool”.  Note that Virtual Accounts can’t be *found* with the Windows Select Users or Groups tool, but if you type in the name specifically, it can be managed there.

Conclusion

Managed Service Accounts are a great way to manage Windows Services that need network access.  Let Windows take care of passwords and SPNs for you. 

Virtual Accounts are great for Windows Services that only need local access.  They are even easier yet.

These new service accounts offer a compelling reason to upgrade to Windows Server 2008 R2 or Windows 7.

Posted: Apr 21 2010, 04:40 AM by OWScott | with 9 comment(s)
Filed under:
URL Parts available to URL Rewrite Rules

URL Rewrite is a powerful URL rewriting tool available for IIS7 and newer.  Your rewriting options are almost unlimited, giving you the ability to optimize URLs for search engine optimization (SEO), support multiple domain names on a single site, hiding complex paths and much more.

URL Rewrite allows you to use any Server Variable as conditions, and with URL Rewrite 2.0, you can also update them on the fly.  To see all variables available to your site, see this post.

An understanding of the parts of a complete URL are essential to working with URL Rewrite, so I’ll include the basics here.  Ruslan Yakushev’s configuration reference was my authoritative source for this.

Take this URL for example:

image

The URL is http://www.bing.com/search?q=IIS+url+rewrite

The parts of the URL are: http(s)://<host>:<port>/<path>?<querystring>

Part Example Server Variable
http(s) http SERVER_PORT_SECURE or HTTPS = on/off
<host> www.bing.com HTTP_HOST
<port> Default is 80 SERVER_PORT
<path> search The rule pattern in URL Rewrite
<path> /search PATH_INFO
<querystring> q=IIS+url+rewrite QUERY_STRING
entire URL path with querystring /search?q=IIS+url+rewrite REQUEST_URI

It’s important to note that /, : and ? aren’t included in some of the server variables. Understanding which slashes are included is important to creating successful rules.

The Mysterious ARR Server Farm to URL Rewrite link

Application Request Routing (ARR) is a reverse proxy plug-in for IIS7+ that does many things, including functioning as a load balancer.  For this post, I’m assuming that you already have an understanding of ARR. 

Today I wanted to find out how the mysterious link between ARR and URL Rewrite is maintained.  Let me explain…

ARR is unique in that it doesn’t work by itself.  It sits on top of IIS7 and uses URL Rewrite.  As a result, ARR depends on URL Rewrite to ‘catch’ the traffic and redirect it to an ARR Server Farm.

As the last step of creating a new Server Farm, ARR will prompt you with the following:

image

If you accept the prompt, it will create a URL Rewrite rule for you.  If you say ‘No’, then you’re on your own to create a URL Rewrite rule.

When you say ‘Yes’, the Server Farm’s checkbox for “Use URL Rewrite to inspect incoming requests” will be checked.  See the following screenshot.

image

However, I’m not a fan of this auto-rule.  The problem is that if I make any changes to the URL Rewrite rule, which I always do, and then make the wrong change in ARR, it will blow away my settings.  So, I prefer to create my own rule and manage it myself.

Since I had some old rules that were managed by ARR, I wanted to update them so that they were no longer managed that way. 

I took a look at a config in applicationHost.config to try to find out what property would bind the two together.  I assumed that there would be a property on the ServerFarm called something like urlRewriteRuleName that would serve as the link between ARR and URL Rewrite.  I found no such property. 

After a bit of testing, I found that the name of the URL Rewrite rule is the only link between ARR and URL Rewrite.  I wouldn’t have guessed.  The URL Rewrite rule needs to be exactly ARR_{ServerFarm Name}_loadBalance, although it’s not case sensitive.

Consider the following auto-created URL Rewrite rule:

image

And, the link between ARR and URL Rewrite exists:

image

Now, as soon as I rename that to anything else, for example, site.com ARR Binding, the link between ARR and URL Rewrite is broken.

image

image

To be certain of the relationship, I renamed it back again and sure enough, the relationship was reestablished.

Why is this important?  It’s only important if you want to decouple the relationship between ARR the URL Rewrite rule, but if you want to do so, the best way to do that is to rename the URL Rewrite rule.  If you uncheck the “Use URL Rewrite to inspect incoming requests” checkbox, it will delete your rule for you without prompting. 

Conclusion

The mysterious link between ARR and URL Rewrite only exists through the ARR Rule name.  If you want to break the link, simply rename the URL Rewrite rule.  It’s completely safe to do so, and, in my opinion, this is a rule that you should manage yourself anyway. 

Posted: Mar 30 2010, 01:38 PM by OWScott | with 8 comment(s)
Filed under: , , ,
500.50 error using URL Rewrite

I ran into a 500.50 error yesterday, which wasn’t very descriptive initially, so I thought I would provide some details on what it could be.

First, off, if you hit the page remotely, it’s going to hide the real details.  It will look something like this:

Server Error

500 - Internal server error.

There is a problem with the resource you are looking for, and it cannot be displayed.

Checking the IIS logs will show that it’s a 500.50 error in this case.

The first thing to do after running into a general error like this is to test it locally on the server.  Now you get a lot more information (I’ve included just some of the error details below):

HTTP Error 500.50 - URL Rewrite Module Error.

The server variable "HTTP_HOST" is not allowed to be set. Add the server variable name to the allowed server variable list.
Detailed Error Information
Module RewriteModule
Notification BeginRequest
Handler StaticFile
Error Code 0x80070005

Now we can tell exactly what happened.  I’m using URL Rewrite 2.0.  Version 2 now allows updating Server Variables.  I tried to update the HTTP_HOST server variable at the site level but forgot to add HTTP_HOST as an approved server variable.

To fix this issue, go to View Server Variables in the Actions pane of URL Rewrite.  Note that you will only see these if you are an administrator on the server.

image

Now add the server variable that you want to change at the site level:

image

That resolved my situation.  However, a 500.50 error can be used for a number of things, always URL Rewrite related. 

Here’s the official description of a 500.50 error:

500.50 - A rewrite error occurred during RQ_BEGIN_REQUEST notification handling. A configuration or inbound rule execution error occurred.

500.51, 500.52 and 500.53 are also URL Rewrite Related: http://support.microsoft.com/kb/943891

Here are a couple other posts of 500.50 situations:

http://forums.iis.net/t/1164360.aspx
http://www.digitalpimple.com/tutorials/windows-tutorials/fix-550-rewrite-error/ (I believe the author meant 500.50)

Hope that helps someone, and happy URL Rewriting!

Posted: Mar 25 2010, 07:04 AM by OWScott | with 3 comment(s)
Filed under: ,
Viewing all Server Variables for a Site

I often do development, testing or troubleshooting where I want to see all server variables available to a site.  For example, when using a reverse proxy for load balancing, SERVER_ADDR, HTTP_HOST and other variables can change.

Whenever I run into that situation, I write out a simple script that displays all server variables.  I thought I would share it here.

Create a file on your server called serversvariables.aspx, test.aspx or whatever you want to call it.  Place the following in it:

<%
For Each var as String in Request.ServerVariables
Response.Write(var & " " & Request(var) & "<br>")
Next
%>

Or if you prefer C#, use the following:

<% @ Page Language="C#" %>
<%
foreach (string var in Request.ServerVariables)
{
Response.Write(var + " " + Request[var] + "<br>");
}
%>

Then simply call the page from a web browser and it will list all server variables. 

The top two variables are worth noting.  They are ALL_HTTP and ALL_RAW which contain all server variables and are repeated with the specific server variables.  Since they contain everything, they can clutter up the page.  You can wrap the Response.Write line in an ‘if’ condition to exclude ALL_HTTP and ALL_RAW if you want, but I find for a quick testing page, I don’t bother, and it gives me every server variable.

The output will look something like this:

{ALL_HTTP and ALL_RAW have been removed from this example.}
APPL_MD_PATH: /LM/W3SVC/2/ROOT
APPL_PHYSICAL_PATH: C:\domains\example.com\
AUTH_TYPE: Forms
AUTH_USER: Scott
AUTH_PASSWORD:
LOGON_USER: Scott
REMOTE_USER: Scott
CERT_COOKIE:
CERT_FLAGS:
CERT_ISSUER:
CERT_KEYSIZE:
CERT_SECRETKEYSIZE:
CERT_SERIALNUMBER:
CERT_SERVER_ISSUER:
CERT_SERVER_SUBJECT:
CERT_SUBJECT:
CONTENT_LENGTH: 0
CONTENT_TYPE:
GATEWAY_INTERFACE: CGI/1.1
HTTPS: off
HTTPS_KEYSIZE:
HTTPS_SECRETKEYSIZE:
HTTPS_SERVER_ISSUER:
HTTPS_SERVER_SUBJECT:
INSTANCE_ID: 2
INSTANCE_META_PATH: /LM/W3SVC/2
LOCAL_ADDR: 206.72.119.72
PATH_INFO: /ServerVariables.aspx
PATH_TRANSLATED: C:\domains\example.com\ServerVariables.aspx
QUERY_STRING:
REMOTE_ADDR: 192.168.168.29
REMOTE_HOST: 192.168.168.29
REMOTE_PORT: 60137
REQUEST_METHOD: GET
SCRIPT_NAME: /ServerVariables.aspx
SERVER_NAME: www.example.com
SERVER_PORT: 80
SERVER_PORT_SECURE: 0
SERVER_PROTOCOL: HTTP/1.1
SERVER_SOFTWARE: Microsoft-IIS/7.5
URL: /ServerVariables.aspx
HTTP_CACHE_CONTROL: max-age=0
HTTP_CONNECTION: Keep-Alive
HTTP_ACCEPT: application/xml,application/xhtml+xml,text/html;q=0.9...HTTP_ACCEPT_CHARSET: ISO-8859-1,utf-8;q=0.7,*;q=0.3
HTTP_ACCEPT_ENCODING: gzip,deflate,sdch
HTTP_ACCEPT_LANGUAGE: en-US,en;q=0.8
HTTP_COOKIE: {removed}
HTTP_HOST: www.example.com
HTTP_MAX_FORWARDS: 10
HTTP_USER_AGENT: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) ...HTTP_X_ORIGINAL_HOST: www.example.com
HTTP_X_ORIGINAL_SERVER_PORT: 80
HTTP_X_ORIGINAL_URL: /ServerVariables.aspx
HTTP_X_FORWARDED_FOR: 192.168.168.29:60137
HTTP_X_ARR_LOG_ID: 3dc509e5-5da8-4b6b-91ee-f084c308e2ce
HTTP_X_SITE_INSTANCE: 01

Hope you find this useful. Happy coding / troubleshooting!

Posted: Mar 09 2010, 08:59 AM by OWScott | with 12 comment(s)
Filed under: ,
IIS URL Rewrite – Hosting multiple domains under one site

In a shared hosting environment, it’s a common desire to have a single IIS website that handles multiple sites with different domain names.  This saves the cost of setting up additional sites with the hoster. 

At ORCS Web, we’ve supported this situation for many years using ISAPI Rewrite.  Now, with URL Rewrite for IIS 7, it’s easier and it’s integrated right into web.config.  In this blog post I’ll set out to cover the essentials for hosting multiple domain names under a single account using URL Rewrite.

This post assumes that you are using URL Rewrite 1.0, 1.1 or 2.0.  I’ll follow-up in a later post on more advanced ways to take this further yet, using the new features of URL Rewrite 2.0.

Part II will cover the outgoing rules available in URL Rewrite 2.0 to take this a step further.

First, the file structure

Let’s lay out the directory structure for this example.  Assume that you have 3 domain names.  They are: masterdomain.com, site2.com and hawaiivisit.site2.com.  You’ve created your directory structure like this:

image

Let’s assume that masterdomain.com was already in the root of the site and can’t easily be moved.  However, site2.com and hawaiivisit.site.com need to be set up.  Each of these folders have a website within them.

Directing the domain name to the server

First, make sure that when you browse to the website by domain name, that it resolves to the correct IP address.  This is handled at the DNS level.  Your DNS entry for site2.com and hawaiivisit.site2.com will often be identical to masterdomain.com and are managed through your DNS provider.

Catching the site when on the server

If you host with a web hosting company then they will take care of this.  If you host yourself, make sure to set a site binding so that the expected site processes the domain name.  If you use host headers, be sure to add the extra bindings for them.

Redirecting the site to a subfolder

Now that you have the domain name directed to the server and site, URL Rewrite comes in to direct it to a subfolder.

First, make sure that your web host supports URL Rewrite on the server that you’re hosted on.  The following assumes that it’s installed and supported.

You can use IIS 7 Manager which gives a friendly interface for creating rules.  If you prefer to write them directly in web.config, I’ll include the rules below.

First, open up URL Rewrite:

image

I’ve come to prefer RegEx rules instead of wildcard rules.  I find that wildcard rules reach their limit pretty quickly.  Regular expressions can be daunting at first but it’s pretty easy to pick up the basics.  Here’s an excellent reference to get started: http://www.regular-expressions.info/reference.html

To create the rule click on “Add Rules…”.

image

Select the “Blank Rule” template and click OK.

For the name, enter your domain name, or whatever makes the most sense to you.

Match URL section

In the Match URL Section, leave the defaults to match the pattern and Regular Expressions.  For the pattern, enter (.*) without the parentheses.  The “URL” is the part after the domain name.  i.e. www.ThisIsTheDomain.com/ThisIsTheURL.  It’s the domain that we’re interested in now, not the URL.

Conditions

The Conditions section is where we’ll do most of the work.  Expand that section if it’s collapsed and click “Add”. 

The domain name is contained within the HTTP header called {HTTP_HOST}.  Here’s where the fun comes.  The regular expression pattern that will match www.site2.com or site2.com (without the www) looks like this: ^(www.)?site2.com$. 

Here’s what that means. 

  • The ^ is the character that signifies the start of the string.  That ensures that something.www.site2.com doesn’t also get included with this rule.
  • The $ is the character that marks the end of the string.
  • ( ) parentheses are used to create section groups. 
  • ? means that something is optional.
  • Therefore, (www.)? means that with www. or without, either are accepted.

After filling in these fields you should have something like the following:

image

Now, here’s the part that many people wouldn’t guess at first.  Since URL Rewrite works on the URL only, while most code (ASP.NET, ASP, PHP, etc) works at the server level, they aren’t aware of each other.  Just because you rewrite the URL doesn’t mean that the code has any clue of the change.  As a result, any time that ASP.NET automatically creates the path, it will likely clash with the URL Rewrite rule.  For example, Response.Redirect(“~/”) will redirect to the root of the application.  That means that it can create a path like www.site2.com/site2.  Notice the extra site2 in the path.  The login page for ASP.NET will mess with you too.

A future blog post will cover how to hide the /site2 using URL Rewrite 2.0, but the easy solution is to ensure that www.site2.com and www.site2.com/site2 both go to the same place.  Both should be served from …\masterdomain.com\site2.  It means that the URL can be longer than you may prefer, but it allows the site to continue to function.

To achieve this, add an exclusion condition so that this rule doesn’t redirect at all if the URL starts with /site2/.

There are 2 ways to achieve this.  You could go back to the URL section where we previously entered .* and update that section.  There isn’t anything wrong with that at all.  For no particular reason that I can think of right now, I prefer to do this from the conditions section.  Here’s how to do it:

Add another condition where the condition input is {PATH_INFO}, and set the dropdown to “Does Not Match the Pattern”, and set the Pattern to ^/site2/.  That means that the PATH_INFO must start with /site2/.  Note that you shouldn’t end with the $ this time because you want sub-sub folders to work too.  It should look like this:

image

Action Section

We’re nearly done.  In the Action section, first set the “Action Type” to Rewrite.  Then set the Rewrite URL to \site2\{R:0} and ensure that the “Append query string” checkbox is checked.  The {R:0} is a back reference to the URL.  It will allow the URL to be carried through dynamically in the request.  The Append query string ensures that the query string itself will carry through.

The complete rule should look like this:

image

That’s it.  Save and test.

Using a Text Editor

You may prefer to use a text editor or to see the config directly.  The rule generated for web.config looks like this:

<rewrite>
    <rules>
        <rule name="site2.com" stopProcessing="true">
            <match url=".*" />
            <conditions>
                <add input="{HTTP_HOST}" pattern="^(www.)?site2.com" />
                <add input="{PATH_INFO}" pattern="^/site2/" negate="true" />
            </conditions>
            <action type="Rewrite" url="\site2\{R:0}" />
        </rule>
    </rules>
</rewrite>

And, the rule for hawaiivisit.site2.com is similar.  It looks like this:

<rewrite>
    <rules>
        <rule name="hawaiivisit.site2.com" stopProcessing="true">
            <match url=".*" />
            <conditions>
                <add input="{HTTP_HOST}" pattern="^hawaiivisit.site2.com$" />
                <add input="{PATH_INFO}" pattern="^/hawaiivisit/" negate="true" />
            </conditions>
            <action type="Rewrite" url="\hawaiivisit\{R:0}" />
        </rule>
    </rules>
</rewrite>

The other things

I wanted to briefly mention what isn’t covered in this blog post that you may want to consider. 

  • DNS. The ‘how to’ for your domain name purchase and directing isn’t covered here.
  • Statistics. If you use  a client-side option like Google Analytics then this will work just as well under a single account.  However, if you are using a log based statistics program like SmarterStats then it’s up to you to set rules in SmarterStats to filter out or sub-divide the statistics into useful sections i.e. 1 per site.
  • Email. You will likely need to setup another mail account with your host, or add the new domain as a domain alias to your existing account.
  • ASP.NET inheritance. web.config inherits down the entire path but the ASP.NET folders do not inherit past application boundaries.  More on that here.  One workaround if ASP.NET inheritance fights with you is to not have a site in the website root.  Instead, place all sites in their own subfolder.
  • You’ll likely need to mark the folder as an application so that it is an ASP.NET application.  (assuming ASP.NET of course)

Happy URL Rewriting!

More Posts Next page »