In this example, I have two sites: The default IIS7 site named “Default Web Site”, and another site named “MySite”.
“Default Web Site” site has a single binding enabling it to receive requests on port 80 of all interfaces, with no specific host header specified. The “MySite” site also listens on port 80 of all interfaces, but it only receives requests that specify “mysite” in the host header. The ability to host multiple sites on a single port using host headers is critical for mass hosting scenarios, and is enabled by the http.sys kernel driver that performs low level request management on IIS’s behalf.
A request to http://domain.com/test/hello.aspx with host: domain is received on port 80, and is dispatched to “Default Web Site”. Then, its routed to the root application, and the root virtual directory within it, and the physical path of the file served for this request becomes c:\inetpub\mysite\test\hello.aspx.
A request to http://mysite.com/ with host: mysite is received on port 80, and is dispatched to “MySite” because it matches the host header specified by “MySite”’s binding. As before, it is routed to the root application, and its root virtual directory, with the physical path being c:\mysite, a directory.
Finally, a request to http://mysite.com/test/hello.aspx with host:mysite is received on port 80, and is again dispatched to “MySite”. It is routed to the root “/” application, but within that application, it is routed to the “/test” virtual directory, because the http://mysite.com/test part of the url matches the virtual directory’s path. So, the physical path of the file served becomes c:\inetpub\test\hello.aspx.
What’s an application pool?
An application pool is technically not a part of the site / application / virtual directory containment hierarchy, but it is an important part of configuring the server to be able to serve requests to the application.
An application pool defines the settings for a worker process that will host one or more IIS7 applications, carrying out their request processing. The application pool is a unit of process isolation, since all request processing for an application runs within its application pool’s worker processes. It is also a unit of isolation from a security perspective since the application pool can run with a different identity, and ACL all needed resources exclusively for itself to prevent applications in other application pools from being able to access its resources.
The application pool mechanism has been introduced in IIS6, and has been a key strategy in supporting IIS6’s stellar security record. In IIS7, it has been further enhanced to offer improved isolation and scalability - I will cover strategies of using application pools efficiently in a future post soon.
So, how do I create a simple IIS7 site?
To summarize what we learned from before, a functioning website is one that has at least the following:
1. A site
2. A binding that determines on which interface, port, and hostheader the site listens on.
3. A root application
4. A root virtual directory mapping the root application to its physical root folder
5. An application pool to run the application
The good news is that IIS7 by default comes with the aptly named “Default Web Site” already configured, so if you are ok with a website on port 80 that listens for all host headers, and a single application located at the root, you can just start using it without having to create anything. Just drop your files in %systemdrive%\inetpub\wwwroot, and hit up http://localhost/.
Given that, why would you want to create a separate website / application / etc? Here are some of the reasons:
1. You want to have multiple websites (different domain names, or ports).
2. You want to have multiple applications to isolate part of your website for reliability, or security reasons by placing them in separate application pools. Or, you need to have separate ASP.NET applications.
3. You want to redirect parts of your website’s url namespace to a different location on disk by creating a virtual directory.
Let’s start with the simplest case - creating a new website from scratch. This post will show how to do these tasks from the command line, but you can do most of these from the new IIS7 Admin tool. The command line is a more flexible way to do it, and lends itself well to automation with cool batch scripts I know you will write.
So, without further ado, let’s create a completely new website using the IIS7’s AppCmd.Exe command line tool, located in %windir%\system32\inetsrv. Be sure to do this as an Administrator from an elevated command line prompt – Start > Programs > right click on Command Line Prompt, and choose Run as Administrator):
> %windir%\system32\inetsrv\AppCmd ADD SITE /name:MyNewSite /id:3 /bindings:http/*:81: /physicalPath:c:\inetpub\mynewsite
SITE object "MyNewSite" added
APP object "MyNewSite/" added
VDIR object "MyNewSite/" added
This creates a new website named “MyNewSite”, with id = 3, and creates a single HTTP binding configured to listen on all interfaces, port 81, without a host-header restriction. Note that a root application, and root virtual directory are automatically created. This is because I specified the optional /physicalPath parameter – which results in the root application with a root virtual directory pointing to the specified physical path to be created. At this point, you can immediately begin using the website by placing files in c:\inetpub\mynewsite, and access the site with http://localhost:81/.
What about the application pool? By default, all applications use the “DefaultAppPool”, a default application pool that also hosts the “Default Web Site”’s application. You can create a new application pool / place the application in a different application pool later if you want.
Going deeper with site, application, and virtual directory creation
Ok, so now we have a simple website we just created. Let’s examine it with the AppCmd List Sites command:
> %windir%\system32\inetsrv\AppCmd LIST SITES
SITE "Default Web Site" (id:1,bindings:http/*:80:,state:Started)
SITE "MyNewSite" (id:3,bindings:http/*:81:,state:Started)
This displays the default and the new site we created, including their ids, their bindings, and their state. The state is a runtime property of the site, and indicates whether the site is currently receiving requests. If there is an error in the site’s definition, for example, another site has a conflicting binding, or the site is missing some required configuration, the state will be “Stopped”. A state of “Started” is a good indication that the site is functional.
You probably noticed earlier that the site binding was specified with the /bindings parameter as “http/*:81:”, which looks like a mangled url. This is the binding syntax used by AppCmd, which allows multiple bindings to be specified in a list of comma-separated PROTOCOL/BINDINGINFORMATION entries, like:
http/192.168.1.1:80:,http/*:81:mysite
This syntax allows bindings to be specified for any protocol, where the PROTOCOL is the protocol name, and BINDINGINFORMATION is a string passed to the listener adapter for this protocol to construct the binding. For HTTP, the binding information string is the following:
[interface-ip-list or * ]:port:[hostheader]
The interface-ip-list is a comma separated list of ipv4 interface addresses on which the binding listens, and * can also be used to mean all ip addresses. The hostheader specifies the request host header value that requests must specify to match this binding, and empty means all host headers.
We also used /id parameter to specify the id for the new site. If you are creating a lot of sites and don’t know which ids are available, you can have the tool assign the next available id by omitting this parameter.
There are times when you do not want to create a root application / virtual directory together with site creation, especially if you require other settings to be set on them – such as specifying the application pool to which the application should belong. In this case, we can create the site, application, and virtual directories separately as follows:
> %windir%\system32\inetsrv\AppCmd ADD SITE /name:MyOtherSite /bindings:http/*:82:
SITE object "MyOtherSite" added
> %windir%\system32\inetsrv\AppCmd ADD APP /site.name:MyOtherSIte /path:/ /applicationPool:MyNewAppPool
APP object "MyOtherSite/" added
I specified the mandatory site name when creating the application, the virtual path, and also optionally set the application pool name for this application. Notice that here you can also use the /physicalPath parameter to force automatic root virtual directory creation.
Now, let’s also create the application pool. For application pools, only the name is required, but you can also set a multitude of application pool configuration settings including identity, recycling settings, etc.
> %windir%\system32\inetsrv\AppCmd ADD APPPOOL /name:MyNewAppPool
APPPOOL object "MyNewAppPool" added
Finally, let’s create the root virtual directory for the application:
> %windir%\system32\inetsrv\AppCmd ADD VDIR /app.name:MyOtherSite/ /path:/ /physicalPath:c:\inetpub\myothersite
VDIR object "MyOtherSite/" added
At this point, we should have a functional site with a root application, and virtual directory. Lets inspect these:
> %windir%\system32\inetsrv\AppCmd LIST SITES
SITE "Default Web Site" (id:1,bindings:http/*:80:,state:Started)
SITE "MyNewSite" (id:3,bindings:http/*:81:,state:Started)
SITE "MyOtherSite" (id:4,bindings:http/*:82:,state:Started)
> %windir%\system32\inetsrv\AppCmd LIST APPS
APP "Default Web Site/" (applicationPool:DefaultAppPool)
APP "MyNewSite/" (applicationPool:DefaultAppPool)
APP "MyOtherSite/" (applicationPool:MyNewAppPool)
Notice that our root app for the MyOtherSIte site we just created is in the MyNewAppPool application pool, as we intended.
> %windir%\system32\inetsrv\AppCmd LIST VDIRS
VDIR "Default Web Site/" (physicalPath:%SystemDrive%\inetpub\wwwroot)
VDIR "MyNewSite/" (physicalPath:c:\inetpub\mynewsite)
VDIR "MyOtherSite/" (physicalPath:c:\inetpub\myothersite)
You will notice that each object has a quoted string right after the object type. This is the unique identifier of the object, which for sites is the site name, for applications is the application config path (site name + virtual path of the application), and for virtual directories is the virtual directory config path ( parent app path + virtual directory path). These identifiers can be used to reference these objects for other operations, such as SET, DELETE, etc.
Finally, during the creation of any of these objects with the ADD command, you can set any of the other configuration properties associated with that object. You can also set them afterwards using the SET command. You can obtain the settable properties for each object, such as below for a site object:
> %windir%\system32\inetsrv\AppCmd SET SITE "Default Web Site" /?
-name
-id
-serverAutoStart
-limits.maxBandwidth
-limits.maxConnections
-limits.connectionTimeout
-logFile.logExtFileFlags
-logFile.customLogPluginClsid
-logFile.logFormat
-logFile.directory
-logFile.period
-logFile.truncateSize
-logFile.localTimeRollover
-logFile.enabled
-traceFailedRequestsLogging.enabled
-traceFailedRequestsLogging.directory
…
For example, to disable logging for a site, you can do:
> %windir%\system32\inetsrv\AppCmd SET SITE "Default Web Site" /logFile.enabled:false
The site object in particular has a lot of different settings that can be set. For more information on how to set these settings, including collection settings, see http://www.iis.net/articles/view.aspx/IIS7/Use-IIS7-Administration-Tools/Using-the-Command-Line/Getting-Started-with-AppCmd-exe?Page=4.
You can also get more help and examples from the tool itself – for example:
APPCMD SITE /? Displays the commands supported by the SITE object
APPCMD LIST SITE /? Displays the help and examples for using the LIST SITE command
The topic of managing sites, applications, virtual directories and application pools is extensive, and so it's hard to cover everything. I hope I got the bases covered, but if you are confused about anything or want more information on any specific issue, please leave a comment. I hope to be able to tune this post to include the stuff you need to know.
Thanks,
Mike