In the course of IIS7 development, the team and I have answered an infinity of questions about IIS7 on any possible topic imaginable.Ironically, neither I nor anyone else I know on the team has ever answered the most basic question - what is the minimum set of steps necessary to get a website running with IIS7?

This post answers this exact question, and explains the key IIS7 concepts of sites, applications, and virtual directories (vdirs), which must be created before your IIS7 server can serve a single request.

Update: We recently launched a service that significantly helps you understand, troubleshoot, and improve IIS and ASP.NET web applications. If you regularly troubleshoot IIS errors, manage Windows Servers, or tune ASP.NET performance, definitely check out the demo at

It also provides the steps necessary to create IIS7 sites, applications, and virtual directories, and options for configuring them.

If you are familiar with IIS6, read on to learn about critical differences in the way sites, apps, and vdirs work on IIS7, and how to create and manage them using IIS7 tools.

If you don’t care about the background, and just want to know how to create your first IIS7 website in the quickest way possible, jump ahead.Then, come back and read about what it all means …

So, what’s the deal with sites, applications, and virtual directories?

Before you can serve a single request from your IIS7 server, you need to create a set of configuration that describes how the server listens for requests, and how these requests are then dispatched to your scripts or static files.To do this, you need to at minimum create a site, an application, a virtual directory, and an application pool, which together provide the basic configuration necessary to serve your website (to be fair, the default configuration of the server already includes a set of these that you can use right away – more on that later).

A site is the top-level logical container that specifies how http requests are received and processed – it defines a group of bindings that determine how the site listens for incoming requests, and contains the definitions of applications/virtual directories that partition the site’s url namespace for the purposes of structuring your application content.

A binding is a combination of protocol name and protocol-specific binding information.While IIS7supports multi-protocol bindings (WCF’s soap-tcp, FTP, etc), we will focus on the http path only here.So, for our purposes an http binding effectively defines an http endpoint that listens on:

·A specific interface ip address (or all interfaces)

·A specific port number

·A specific http host header (or all host headers)

This way, you can configure many sites on your server that listen on different ip addresses, different ports, or on the same ip address / port but with different host headers.

It’s important to note that the url of the request has no part in determining which site the request is routed to – only the bindings do.All requests received on a binding are sent to the site that owns the binding, so effectively each site owns its own full url namespace starting with “/”.
This url namespace is then partitioned further into applications, and then further yet by virtual directories.

An application is a logical container of your website’s functionality, allowing you to divide your site’s url namespace into separate parts and control the runtime behavior of each part individually.For example, each application can be configured to be in a separate application pool, thereby isolating it from other applications by putting it in a separate process, and optionally making that process run with a different Windows identity to sandbox it.The application is also the level at which ASP.NET applications / appdomains are created.

Each application has a virtual path that matches the initial segment of the url’s absolute path for the requests to that application.A request is routed to the application with the longest matching virtual path.
- Each site must have at least the root application with the virtual path of “/”, so any requests not matching other applications in the site will be routed to the root application.

Finally, a virtual directory maps a part of the application url namespace to a physical location on disk.When a request is routed to the application, it uses the same algorithm to find the virtual directory with the longest virtual path matching the remainder of the request’s absolute path after the application path.
- Again, each application must have at least the root virtual directory with the virtual path of “/” to be functional.

For example, here is how a request to /app1/dir1/file.txt may be routed based on site layout:

Site layout

Request routing

“/” APP
“/” VDIR

“/” APP, “/” VDIR

“/” APP
“/” VDIR
“/app1” APP
“/” VDIR

“/app1” APP, “/” VDIR

“/” APP

“/” VDIR
“/app1/dir1” VDIR
“/app2” APP
“/” VDIR

“/” APP, “/app1/dir1” VDIR

Let’s look at an example:

IIS7 Site containment hierarchy

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 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:inetpubmysitetesthello.aspx.

A request to 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 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 part of the url matches the virtual directory’s path.So, the physical path of the file served becomes c:inetpubtesthello.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%inetpubwwwroot, 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%system32inetsrv.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%system32inetsrvAppCmd ADD SITE /name:MyNewSite /id:3 /bindings:http/*:81: /physicalPath:c:inetpubmynewsite

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:inetpubmynewsite, 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%system32inetsrvAppCmd 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:


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%system32inetsrvAppCmd ADD SITE /name:MyOtherSite /bindings:http/*:82:

SITE object "MyOtherSite" added

> %windir%system32inetsrvAppCmd ADD APP / /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%system32inetsrvAppCmd ADD APPPOOL /name:MyNewAppPool

APPPOOL object "MyNewAppPool" added

Finally, let’s create the root virtual directory for the application:

> %windir%system32inetsrvAppCmd ADD VDIR / /path:/ /physicalPath:c:inetpubmyothersite

VDIR object "MyOtherSite/" added

At this point, we should have a functional site with a root application, and virtual directory.Lets inspect these:

> %windir%system32inetsrvAppCmd 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%system32inetsrvAppCmd 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%system32inetsrvAppCmd LIST VDIRS

VDIR "Default Web Site/" (physicalPath:%SystemDrive%inetpubwwwroot)
VDIR "MyNewSite/" (physicalPath:c:inetpubmynewsite)
VDIR "MyOtherSite/" (physicalPath:c:inetpubmyothersite)

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%system32inetsrvAppCmd SET SITE "Default Web Site" /?















For example, to disable logging for a site, you can do:

> %windir%system32inetsrvAppCmd 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

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.