Going Live with IIS 7.0
At a Glance:
- Deploy IIS 7.0 in a Web farm environment
- Security and performance enhancements
- Migrate ASP.NET Web apps from IIS 6.0 to IIS 7.0
- Migrate PHP Web apps to IIS 7.0
Code download available at: IIS72008_07.exe (861 KB)
The IIS team at Microsoft says Internet Information Services (IIS) 7.0 is the biggest release in the history of IIS. This version sets new standards, offers fundamental improvements, and
brings new capabilities for consolidating Web environments. IIS 7.0, which is included with Windows Server® 2008 and Windows Vista® SP1, already powers Microsoft.com, and several Web hosting companies have already started to provide IIS 7.0 hosting to Web designers and developers who want to port their existing Web apps to the new Web server platform.
In this article, I will explore key IIS 7.0 enhancements that are most important for IT professionals, and then I'll go into detail about migrating ASP.NET and PHP Web applications. But first I want to outline a test lab that resembles a basic production environment.
This is an important task. Before you deploy IIS 7.0 to your production servers, you need to spend time doing thorough testing in a lab environment to ensure your Web apps run smoothly on the new Web server.
Ready, Set, Test
My test lab includes systems running Windows Server 2003 and IIS 6.0, which host ASP.NET applications, as well as servers running the Ubuntu 7.10 Linux distribution and Apache HTTP Server 2.2, which host PHP-based Web applications. My ultimate goal is to deploy Windows Server 2008 on staging and production systems and then transition complex Web applications in order to replace IIS 6.0 and Apache instances with IIS 7.0.
I have two key Web apps: DotNetNuke 4.7 and osCommerce 3.0a4. DotNetNuke is a Web app framework based on ASP.NET 2.0 and Microsoft® SQL Server®. The other application, osCommerce, is the latest alpha version of a full-featured e-commerce solution built on PHP and MySQL. So let's put these advanced applications on IIS 7.0!
I want to be clear that it is not my intention to compare software versions, products, or platforms. There are, however, a number of advantages to standardizing on Windows Server 2008 and IIS 7.0 that I should point out. Namely, administrative complexity is reduced and you can minimize the overall number of Web servers you are running.
Figure 1 provides an overview of the test lab I am using for this article. If you want to follow my explanations in your own test environment, you can find links to required software components as well as detailed, step-by-step installation instructions in the companion material available from the Code Downloads section of the TechNet Magazine Web site at .com.
Figure 1 The test environment for rolling out IIS 7.0 (Click the image for a larger view)
Note that around the time I was wrapping up this article, Microsoft released a command-line tool (MSDeploy.exe) to support customers deploying, synchronizing, and migrating Web applications to IIS 6.0 and 7.0. I recommend that you check out this tool. Detailed information can be found on the Microsoft Web Deployment team blog at go.microsoft.com/fwlink/?LinkId=118272.
My Test Setup
At the time of this writing, Windows Server 2008 was still in a pre-release, so I therefore did not replace Windows Server 2003 on domain controller or database servers. With the official release of Windows Server 2008, you may want to consider migrating your Active Directory® infrastructure as well. Migrating SQL Server® 2005 and MySQL databases to SQL Server 2008 is also beyond the scope of this article.
I deployed SQL Server 2008 on my staging server mainly because it takes less effort than installing SQL Server 2005 with Service Pack 2. DotNetNuke had no problems running with a SQL Server 2008 database. Installing MySQL 5.0 on Windows Server 2008 was also straightforward with no complications.
While IIS 7.0 is available on Server Core, I did not use a Server Core installation due to certain requirements for my testing. My staging server required a full installation because this was my primary test system. In addition, the Microsoft .NET Framework is not available on Server Core.
PHP runs fine on Server Core, but my goal is to consolidate ASP.NET and PHP applications, so Server Core simply isn't an option. Until the .NET Framework is supported on Server Core, you'll need to perform a full installation to support ASP.NET apps. For detailed step-by-step guidelines to install the test environment, check out the 01_install_testlab.htm file in the companion material.
I opted to perform a clean install of Windows Server 2008 (as opposed to upgrading existing servers). Among other things, the clean installation makes it easier to implement a staged migration scenario like the one in Figure 2. The underlying strategy is to keep the existing Web farms running until all relevant Web app components have been successfully tested on the staging server and moved to the new IIS 7.0 Web farm.
Figure 2 Staging the switch to IIS 7.0 (Click the image for a larger view)
You can move all existing Web applications at once or gradually, depending on the complexity of your environment. For each Web application or site, after performing a final acceptance test on the new Web farm, you can make the switch by changing relevant DNS records to direct browsers to the new IIS 7.0 Web farm. This keeps downtime and interruptions to a minimum.
Important Enhancements for IT Admins
MSDN® Magazine has an excellent article by Mike Volodarsky titled "Explore the Web Server for Windows Vista and Beyond" (available at msdn2.microsoft.com/magazine/cc163453.aspx), which quickly brings you up to speed on improvements found in IIS 7.0.
Another good read is a blog post from the Microsoft.com team, titled "The Tasty Morsels Found in Dogfood" (available at go.microsoft.com/fwlink/?LinkId=117436). The post summarizes the team members' initial IIS 7.0 experiences. In a nutshell, they ranked the top improvements as:
- Simplified setup.
- Great compatibility.
- No more metabase.
- Centralized configuration is through applicationHost.config file placed on a UNC share.
- Delegated configuration by means of web.config files in application directories
- Improved management tools.
- Failed-request tracing.
- Request filtering without the need for URLScan.
- Simplified content synchronization availability through UNC shares.
10.Output caching of dynamic content.
Simplified setup is definitely on my list. In its blog post, the Microsoft.com team demonstrates how you can deploy all the features of IIS 7.0 (or, of course, just the features you want) with a single command line. I eagerly incorporated this approach into my test lab setup instructions, with the command line shown in Figure 3.
Admittedly, this command is rather long. (If you want to copy this command, I recommend you copy and paste it from the TechNet Magazine Web site rather than retype it by hand.) Although this command puts all available modules on the IIS 7.0 computer, it doesn't include PHP. IIS 7.0 doesn't include PHP, and the notion of downloading and installing Debian packages over the Internet is a foreign concept for the Windows® Package Manager (pkgmgr.exe). Enter the Windows Automated Installation Kit (AIK).
Figure 3 Deploying IIS 7.0 features with a single command line
With AIK, you can create a custom installation DVD for Windows Server 2008 that includes IIS 7.0 and PHP 5. You can also include MySQL, Web application files, and any other components that are needed in your deployment. All the components can be part of your Windows Server 2008 Setup, allowing you to apply customizations consistently on all your Web servers. There's no need for command lines or configuration file editing.
You can even create a custom DVD for fully unattended installations. The AIK includes documentation and tools to create an AutoUnattend.xml file, which you then place in the DVD's root folder. The Custom Image Deployment.htm file in the companion material offers step-by-step instructions.
Many administrators also agree that compatibility is a key improvement. Going in, I expected to encounter a few compatibility issues with DotNetNuke and osCommerce, but the transition to IIS 7.0 was rather painless, despite the fact that both of these Web applications include advanced features, such as forms authentication and search-engine-friendly URLs.
With DotNetNuke, I did not encounter any issues until I moved to a complex Web farm scenario with UNC content sharing on a 64-bit platform. The issue, however, was fairly minor. Ultimately, this improved compatibility means less time is required to get your Web applications running on IIS 7.0.
If you happen to encounter compatibility issues with your Web applications, the built-in diagnostics and tracing support will quickly become one of your favorite new features. The detailed diagnostics information is very meaningful, and the suggested solution paths are useful and actually work.
Figure 4 shows the diagnostics information you get when running DotNetNuke 4.7 on IIS 7.0 in integrated mode. In this example, there are three options (shown in the "Things you can try" section). Changing the application to support integrated mode is probably the best choice for DotNetNuke developers. Ignoring the error is probably a bad idea. I like the third choice, enabling classic mode by switching the Web app to the Classic .NET AppPool, because I want to run DotNetNuke 4.7 unmodified on IIS 7.0.
Figure 4 Diagnostics information for DotNetNuke running in integrated mode (Click the image for a larger view)
You might be wondering what these integrated and classic modes are and why they affect the ASP.NET application (DotNetNuke) but not the PHP application (osCommerce). To better understand this, you must first take a look at the architecture of IIS 7.0. Previous versions integrate the ASP.NET runtime into the core Web server, primarily through an ISAPI extension (aspnet_isapi.dll). IIS 7.0, on the other hand, allows ASP.NET modules to plug directly into the core Web server through a global-level HTTP module called ManagedEngine, which loads the ASP.NET Support DLL (webengine.dll) into the IIS 7.0 request processing pipeline.
Native modules use the IIS Web Server Core API to register for specific events in the pipeline, such as BeginRequest, AuthenticateRequest, AuthorizeRequest, and ExecuteRequestHandler. ManagedEngine provides the necessary support to integrate ASP.NET modules into the request pipeline as well. With this new architecture, IIS 7.0 can invoke native and ASP.NET modules at any stage during request processing regardless of the requested content type.
As an example, let us consider ASP.NET user authentication. In IIS 6.0, it is possible for an ASP.NET-based HTTP module to register for OnAuthenticate events (such as FormsAuthentication.OnAuthenticate and WindowsAuthentication.OnAuthenticate) to set the identity of the user in the current HttpContext. This works great inside the ASP.NET runtime, but you cannot use this ASP.NET code to protect resources exposed through a PHP-based Web application.
According to its scriptmap configuration, IIS 6.0 forwards requests for ASP.NET content types to aspnet_isapi.dll, but it doesn't forward requests for PHP content types to the ISAPI extension for ASP.NET. After all, ASP.NET doesn't process PHP code, but it also means that the ASP.NET authentication code does not run if a PHP page is requested. Thus, with IIS 6.0, you need to duplicate the authentication logic because PHP applications must implement their own authentication mechanisms.
IIS 7.0 uses an event-driven processing model that supports mixing and matching individual modules in the request pipeline. Among other components, IIS 7.0 comes with managed WindowsAuthentication and FormsAuthentication modules that raise OnAuthenticate events when the request pipeline fires the AuthenticateRequest event. You can now have a native module, such as RequestFilteringModule or IpRestrictionModule, handle the BeginRequest event to reject critical requests as early as possible, then run custom ASP.NET authentication code at the AuthenticateRequest event and have the FastCgiModule run the PHP scripting engine (php-cgi.exe) at the ExecuteRequestHandler event to process PHP pages.
The result of this integrated architecture is that Web developers don't have to duplicate code to implement common business logic. You can use custom ASP.NET authentication code to protect all your IIS resources including PHP applications. And you can perform other pre- and post-processing tasks through ASP.NET modules, such as URL rewriting, custom tracing, and error logging.
Integrated and Classic Modes
The side effect caused by this new architecture is that existing ASP.NET applications might require code and configuration changes that should be performed by application developers to ensure that the changes don't lead to module conflicts in the request pipeline. But if you can't immediately port an existing Web application, you can enable classic mode in the app pool that the worker process uses to run the Web application. IIS 7.0 does not load ManagedEngine into classic-mode worker processes, which implies in this case that the request pipeline cannot resolve or invoke ASP.NET modules. Instead, IIS 7.0 activates a number of ISAPI handlers, which are based on IsapiModule (aspnet_isapi.dll), to process ASP.NET content types similar to IIS 6.0. You can see this if you analyze the handlers section under system.webServer in the applicationHost.config file, which you can find by default in the %WinDir%\System32\InetSrv\Config folder.
Search for the string aspx as an example and you will find one entry pointing to PageHandlerFactory-Integrated (loaded into integrated-mode application pool worker processes according to the setting preCondition="integratedMode") and other entries pointing to PageHandlerFactory-ISAPI-2.0 and PageHandlerFactory-ISAPI-2.0-64 (loaded into classic-mode application pool worker processes according to the setting preCondition="classicMode").
Because the pipeline mode is set at the application pool level, IIS 7.0 can run Web applications in integrated and classic mode simultaneously. And the worker processes only need to run in different application pools but can be hosted on the same server.
Keep in mind that integrated mode and classic mode only affect how IIS 7.0 integrates ASP.NET into the request pipeline. These pipeline modes do not affect PHP applications directly. The FastCgiModule and all other native modules load without pipeline-mode preconditions in both integrated mode and classic mode. FastCGI is the preferred interface to run the PHP scripting engine on IIS 7.0. Instead of using FastCGI, you can also create a handler mapping for the PHP scripting engine through CGI, or you can use the IsapiModule in conjunction with PHP-ISAPI (php4isapi.dll).
I, however, think these IIS 6.0-style configuration alternatives are outdated now that FastCGI offers substantially improved performance and stability. CGI is slower since IIS must initialize a new CGI process for every HTTP request while FastCGI reuses CGI processes for multiple requests. ISAPI requires a thread-safe PHP build, which involves more overhead than running non-thread-safe PHP.
Perhaps even more important, not all PHP extensions are available in a thread-safe version, and running non-thread-safe extensions with ISAPI is a bad idea because it can cause stability issues on the server. FastCGI, on the other hand, is a single-concurrency environment like CGI. Used to run non-thread-safe PHP, FastCGI is stable and fast, and it is clearly the way to go with PHP 5 on IIS 7.0. It is also available on IIS 6.0 if you are not yet ready for a transition to IIS 7.0.
Modules and Functionality
IIS 7.0 features a highly modularized architecture—or, as the IIS developers put it, a componentized feature set. This is good news for Web administrators who want to keep the memory footprint and attack surface of IIS 7.0 as small as possible. By enabling different modules or perhaps even replacing standard modules with custom modules, you can gain complete control over the IIS 7.0 features on your Web servers.
To run ASP.NET in integrated or classic mode, as well as PHP applications on the same server, you must install at a minimum the Web Server role and the core modules to support request processing, server configuration, ASP.NET, ISAPI, and CGI (which includes the FastCGI module). This can be done with the following command line:
start /w pkgmgr /iu:IIS-WebServerRole; WAS-WindowsActivationService;WAS-ProcessModel; WAS-ConfigurationAPI;IIS-ASPNET; IIS-NetFxExtensibility;WAS-NetFxEnvironment; IIS-ISAPIExtensions;IIS-ISAPIFilter;IIS-CGI
I generally prefer to install IIS 7.0 with all available options on my staging server to ensure that all components and administrative tools are available to get my Web applications up and running quickly. My strategy is to make sure things are working, and then I narrow down the configuration by uninstalling role services and disabling modules. When a Web app starts to act up, I add back role services or modules I just removed.
You also have the choice of using Package Manager (pkgmgr.exe) or the IIS 7.0 command line tool (appcmd.exe) or editing the globalModules section in the applicationHost.config file directly, but I find the graphical tools very convenient. Keep in mind that some modules, such as RequestFilteringModule and StaticCompressionModule, are quite useful even though they are—strictly speaking—not needed for your Web applications to run. If you uninstall a module that is required for an application pool, you will receive an HTTP error when accessing your Web application, as illustrated in Figure 5.
Figure 5 An ASP.NET application won't run in classic mode because IsapiModule is missing(Click the image for a larger view)
Note: as a best practice, make sure the same set of modules is installed and enabled on all of your IIS 7.0 servers. To verify the installed components, go to HKEY_LOCAL_MACHINE\Software\Microsoft\InetStp\Components\ and check the registry keys. A REG_DWORD value of 0000 0001 for a registry key, such as for NetFxEnvironment or CGI, indicates that the corresponding component is installed.
Web Application Migration
Enough theory, now it's time to roll up my sleeves and move some Web applications to IIS 7.0. As mentioned earlier, my staging server runs IIS 7.0 with all available components and non-thread-safe PHP 5 registered with FastCGI. Before I begin, I need to ask a few basic questions:
- Does the Web application require a database management system, such as SQL Server or MySQL?
- Do I need to install or configure additional components, such as ODBC connections, COM objects, or SSL certificates?
- Does the Web application require special service accounts and elevated local or remote access permissions to file shares and other resources?
- Are there any dependencies on platform-specific features that are unavailable on IIS 7.0, such as dependencies on the Apache module for URL rewriting (mod_rewrite)?
Asking questions like these will help get your Web apps running on IIS 7.0 faster. For example, if you are trying to migrate a PHP application from Apache 2.2 that uses mod_rewrite (say, for search-engine friendliness or to prevent bandwidth hijacking through inline-linked images), you will have problems until you implement a compatible custom URL rewriting solution on IIS 7.0. Fortunately, osCommerce does not require mod_rewrite functionality on IIS 7.0, but some search engine optimization packages might.
Now that I have determined and installed the required additional components on the staging server, I am ready to get my Web applications up and running. Again, there are a few questions that I want to ask myself:
- What is the simplest configuration I can use to support the Web application?
- What configuration is currently used in the production environment?
- Can I optimize the Web application configuration on the new platform?
- What is the minimum set of role services and modules that the Web app needs to function in the desired configuration?
Getting the Web application running in the simplest configuration is a quick way to make sure that it works. If everything looks great, it is time to apply a configuration similar to the existing production environment and import production data into the test databases. Of course, some issues might only surface in advanced configurations.
You might also notice opportunities for improvements when mirroring your production configuration in a test lab. Placing the applicationHost.config file on a UNC share is a great way to centralize the configuration of multiple Web servers. To increase fault tolerance through redundancy and content synchronization, consider implementing Distributed File System (DFS) Replication, which is a state-based multimaster replication engine available with Windows Server 2003 R2 and Windows Server 2008. You can also minimize storage requirements on Web front ends by placing the content files of your Web applications on UNC shares.
Other potential optimizations may involve security or dynamic caching. I didn't address security and performance optimizations in my test lab because that is beyond the scope of this article. Nor did I configure DFS to avoid the installation of further servers. The step-by-step instructions in the companion material provide a simplified example of how to host applicationHost.config file and Web content on UNC shares. And Figure 6 illustrates how to implement a UNC-based Web farm with DFS.
Figure 6 Web farm deployment with applicationHost.config file and Web content on UNC shares (Click the image for a larger view)
IIS 7.0 is an impressive Web server platform. It features a redesigned core architecture while maintaining nearly 100 percent backward compatibility with IIS 6.0. It should be able to run most existing ASP.NET Web applications without modification. But given the extent of the architectural changes, you cannot assume that you won't encounter compatibility issues.
Whether you are migrating ASP.NET or PHP Web apps to IIS 7.0, it's best to take a staged approach with emphasis on proper planning, preparation, testing, and documenting code and configuration changes.
IIS 7.0 is worth the work involved. There are many improvements in areas such as security, performance, configurability, and flexibility. It would take an entire book to discuss them all. Centralized configuration and content sharing based on UNC shares, delegated configuration by means of web.config files in application directories, improved management tools, detailed diagnostics information and failed-request tracing, and dynamic output caching are surefire ways to win the hearts of Web administrators.
The capability to mix native and managed modules in the request processing pipeline benefits ASP.NET developers. And the performance and stability improvements that come with FastCGI on IIS 7.0 are excellent news for PHP application developers.
And there is one more important thing that helps IT pros to be successful with IIS 7.0: the Microsoft IIS Community Portal (www.iis.net). It contains all the information you need, including detailed articles about the new architecture, source code for C++ and ASP.NET developers demonstrating how to create IIS 7.0 modules, and step-by-step instructions to get PHP applications up and running. You'll definitely want to check out this site. It's a good first stop for answers to your IIS-related questions.