IIS Web Server Best Practices

Best practices I use when setting up IIS: – Each site should be a separate (sub-)domain.  Thus http://somesite.mycompany.com/ instead of http://www.mycompany.com/somesite/  This solves a few problems: “../../don’t/do/this.jpg” is avoided when you can presume the root of your site is “/”, which means you can avoid relative paths (even if you need not crawl up a directory) and you can avoid the ~.  It’s much cleaner all the way around. – Because each site is its own (sub-)domain, you also avoid the pitfall of virtual directories.  A virtual directory is an app within an app.  (http://www.mycompany.com/otherapp/) and some changes to the outer app cascade into the inner app.  For example url rewrite rules, authentication, dll mapping, etc.  Basically the system starts at your app’s directory’s web.config, crawls up the folder stack layering behind every web.config it finds, layers behind that the web.config in the framework directory, and finally machine.config.  This is why you need not copy every changes in your regular web.config into the web.config in the Views folder in MVC.  Because a virtual directory is by definition an app inside another app, of necessity you’ll inherit the outer app’s web.config, potentially negatively impacting your app as their app evolves. – The app pool is the execution space, so, each site should have its own.  That doesn’t completely protect you from another site blowing up your site, but it does help considerably.  Especially if a technician needs to recycle the app pool as part of an app upgrade or if only one site on the machine is having troubles. – If you consistently change things on all sites like removing headers, configuring additional mime-types, rearranging or removing default document names, setting the error pages, etc, do these on the machine node in IIS rather than redundantly for each site. – ASafaWeb.com is a great tool for highlighting configuration errors and places where you’re exposing more information than necessary. – Make sure you handle the “naked domain” (zone apex).  Mapping to www.mysite.com is important, but users could just as easily hit mysite.com (without the www) and if your site doesn’t handle both, a consistent portion of your users will consider your site “broken”.  For SEO purposes, permanently redirect one to the other.  (Which you choose is likely a matter of corporate culture or preference, and ultimately is irrelevant … provided you consistently choose it in IIS configurations, Google Webmaster Tools, etc.) – If at all possible, run the apps in the most recent framework version, in “Integrated” mode, with 32-bit disabled, with modern .net frameworks installed on the box, and all Windows Updates.  Ideally you’ll also be on the most modern OS version too.  Your apps may need code changes to make this possible.  These are the defaults with new installs and are promoted as “modern techniques” [read: best practices], and ensuring your apps are compliant suggests future deployments to similar or newer hardware or OSs will be less traumatic. – c:\inetpub\wwwroot\myapp is a very awful place to put your web site folder.  Because this is the default, if I’m a hacker trying to compromise your site and I find another way into your box (FTP, RDP, network share, etc) I can stick something in all such folders and compromise every site on the box.  Script kiddies have automated attack tools that can do this.  Instead, I create a folder like C:\Internet\ or C:\Websites\ or similar.  Inside, I have a folder for each site with sub-folders for:

  • db
  • logs
  • www I’ll then put the IIS website content in the www folder, point IIS to put the site’s logs into the logs folder, (Ever crawl through IIS’s default log folder trying to figure out which log folder you want?  I’m sorry, “W3SVC6” is not sufficiently descriptive.) and if SQL Server is on the same machine (not best practice), point it to put the mdf and ldf files into the database folder.  Now when you want to backup “everything”, just stop IIS, stop SQL, and copy C:\Internet.  You got “everything” for all sites on the box (with the exception of C:\Windows\System32\inetsrv\config\applicationHost.config which you should also backup periodically.) – applicationHost.config is not scary.  It’s the “Metabase” (using IIS 6’s term) and is just an xml file.  From time to time, IIS’s GUI has a wacky limitation or I want at it faster than that, so I just pop open C:\Windows\System32\inetsrv\config\applicationHost.config using an elevated notepad and hack away.  Want to setup the second server in the farm to exactly match the first?  Install IIS, install all the plugins you need via Web Platform Installer, run windows update a few times, then use Beyond Compare or WinMerge to diff old box’s applicationHost.config to new box’s, and copy across.  Ta-da!  Instant second box.  (BTW, don’t copy over the “encryption key” lines nor module or handler lines for plugins you didn’t install, and make careful backups before changing this file.  Either that, or you can get good at reformatting boxes.  I needed only make that mistake once.  :D)  Of particular interest in applicationHost.config is the node. – One of the big challenges with IIS is “who owns the site’s web.config: The IT dept or developers?“  This is because site-specific changes made in IIS are stored in the app’s web.config.  (This is also why php and node apps hosted on windows have a web.config file even though they don’t use .net.) Alter the list of default documents or change the authentication scheme, and it’ll write these nodes into web.config.  On next deploy if you flush and reset everything – including web.config – you’ll remove these settings.  Oops.  (Also see the “if you do it on every site, do it to the box not to each site” note above.) – The remote management service is incredibly cool.  

http://www.iis.net/learn/manage/remote-administration/remote-administration-for-iis-manager  Typically the only reason we RDP to the IIS machine is to use IIS Manager, run windows updates, or figure out why it ran out of hard drive space.  It is an increased attack surface to have the management service on, so perhaps configure the firewall to only expose port 8172 (or the one you configure) to the LAN and not to the public.  Now no more RDPing for config changes. I’m confident this is hardly an exhaustive list, but based on these, you can get to a pretty good place in IIS, and probably get the Google-fu cranked up too.  Happy hosting! Rob