11+ Tips to optimize Umbraco 7 CMS

11+ tips to optimize Umbraco 7 performance on Windows Server
Published on Wednesday, 7 November 2018

Official Umbraco 7 logo

Umbraco 7 is a popular, ASP.NET powered, content management system (CMS). Out of the box Umbraco performs pretty well, but there are still some areas you need to tweak and tune for a more performant Umbraco website. Here are 11+ tips.


More and more up-to-date information is in my How to optimize Umbraco 8 performance post.

Optimize Umbraco 7 and make it a bit more efficient

You can make a couple of changes to Umbraco 7 to make it a bit more efficient. Use these tips to your advantage, to make Umbraco perform better, but some tips may require assistance of your Windows Server IIS web server administrator. Remember him next System Administrator Appreciation Day :-)

some settings don't work for Umbraco v8! Please note that I'm not an ASP.NET programmer.

Key for a better performing Umbraco website is less writing to disk, or reading from disk. I find that a bottleneck, even with SSD's. Less reading and writing also saves on RAM (memory) and CPU usage, and thus process execution time in IIS.

In no particular order I'll address the following topics. You can configure these settings to make Umbraco perform better, make it use less memory and CPU %.

  • ASP.NET Compilation tempDirectory
  • NumRecompilesBeforeAppRestart
  • File Change Notification (FCN)
  • Disable ~/App_Data/umbraco.config
  • Umbraco ModelsBuilder ModelsMode
  • HTTP Expires headers
  • ~/Config/log4net.config
  • ~/Config/ExamineSettings.config
  • ImageProcessor cache folders, ~/Config/imageprocessor/cache.config
  • AllowSubDirConfig, SqlCe database file to SQL Server
  • SQL Server sessionState

Some changes might degrade performance, especially when done wrong. When in doubt, consult your system administrator first. These settings below work in my environment, maybe not yours.

Did you route Umbraco to HTTPS already? It's in Dutch, but you can read the code.

ASP.NET Compilation tempDirectory

All to often in a shared hosting environment, you may share your ASP.NET compilation temporary directory with other users. This may not be particularly a bad thing, but when a lot of IIS worker processes are reading and writing in one directory, you may find your website waits for other disk operations. And that takes time.

If ASP.NET 4 runs in a Full trust configuration, you can overwrite ASP.NET's compilation tempDirectory setting to a folder in your website. For example, if the physical path to the content for the virtual directory of your website is z:\shared\sites\example.com\www, and the msIIS-FTPRoot is configured as z:\shared\sites\example.com, you can create an extra folder temp in the FTPRoot and configure that as your compilation tempDirectory.

Locate Umbraco's compilation node in <system.web>, and add the tempDirectory:

<compilation
  tempDirectory="z:\shared\sites\example.com\temp"
/>

Make sure this folder is writable for the user your website runs as.

NumRecompilesBeforeAppRestart

Indicates the number of dynamic recompiles of resources that can occur before the application restarts. This attribute is supported at the global and application configuration levels, but not at the directory configuration level.

ASP.NET increases the NumRecompilesBeforeAppRestart property value every time an assembly is invalidated and fails to be deleted.

By default, IIS restarts the Umbraco web application after 15 dynamic recompiles of resources. When you have a large Umbraco website, you may experience a long time before the compilation process of your scripts is finished. During the compilation, CPU usage spikes and your sites become unresponsive.

You can decrease the number of application restarts by increasing the NumRecompilesBeforeAppRestart property in your web.config file. Umbraco has this value set to 50, you can increase this to 150, 200, or whatever:

numRecompilesBeforeAppRestart="150"

This is also found in the compilation node in your web.config.

File Change Notification (FCN)

Change the file change notification in ASP.NET, so less resources are used for keeping track of changed files. Especially in large media folders FCN can degrade performance. The All about ASP.Net File Change Notification (FCN) post on Shazwazza's blog has more insights about this. Locate the httpRuntime key in your web.config and add fcnMode="Disabled" to completely disable File Change Notification for that folder, or set it to Single. Single is the default since Umbraco 7.5.3, see U4-7712.

Disable ~/App_Data/umbraco.config

Every time you publish a page in Umbraco, the ~/App_Data/umbraco.config file is saved as cache. In ASP.NET's mind this is a configuration change, and the application is restarted by IIS with reason ConfigurationChanged.

This behavior is easily disabled in ~/Config/Umbracosettings.config:

  • add the following two (2) lines to ~/Config/umbracoSettings.config:
    • <ContinouslyUpdateXmlDiskCache>False</ContinouslyUpdateXmlDiskCache>
    • <XmlContentCheckForDiskChanges>False</XmlContentCheckForDiskChanges>
  • delete the ~/App_Data/umbraco.config file!

This is addressed in U4-7101. I had to fiddle a bit with where to put these lines, and after some testing, lines 38/39 seemed fine.

Umbraco ModelsBuilder ModelsMode

The thing I could not test, unfortunately: Umbraco ModelsBuilder ModelsMode.

Umbraco ships with a NuGet package called ModelsBuilder. This generates strongly typed models that can be used in Umbraco views. The default behaviour is to generate the models on the fly, in memory, at runtime. This has the advantage of the models always being up to date whenever a content type is modified.

[...]

We changed the setting to Dll mode, which compiles the models to a Dll that is then copied into the bin folder. This fixed the 10s slowdowns, and also fixed the Max Recompilations Reached errors we were seeing above. The downside with this is that it requires a manual step after a deploy to build the models from within the back office.

HTTP Expires headers

Expires headers? Yes, expires headers. Apparently, they're not set everywhere for your static Umbraco resources.

By configuring expires headers you tell the browser to keep a local copy of the resource in its cache. This speeds up a next visit or page view. The following example, that you add to your web.config tells the browser to save it for 14 days, change the duration if you'd like.

First determine which folders you have in your Umbraco installation, and then select the appropriate lines to add.

<location path="Umbraco_Client/assets">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
    </staticContent>
  </system.webServer>
</location>
<location path="Umbraco_Client/Js">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
    </staticContent>
  </system.webServer>
</location>
<location path="css">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
    </staticContent>
  </system.webServer>
</location>
<location path="Media">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
    </staticContent>
  </system.webServer>
</location>
<location path="scripts">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="14.00:00:00" />
    </staticContent>
  </system.webServer>
</location>

There already is a line <location path="umbraco"> in your web.config, add the three lines there as well.

keep in mind the folders above may differ in different Umbraco versions. Not every version has an umbraco_client directory present.

Want to learn more about HTTP headers? For example, learn how to remove IIS Server version header.

~/Config/log4net.config

If you don't use the logfiles Umbraco creates through log4net, then log as less as possible. This limits the number of writes to your disks. In the file ~/Config/log4net.config change the value "true" in "false" for the key <appendToFile value="true" /> and WARN in ERROR for <level value="WARN" />.

~/Config/ExamineSettings.config

Umbraco Examine is an extensible indexer and search engine. Add useTempStorage="Sync" to the nodes as described in U4-5993 and https://our.umbraco.com/forum/umbraco-7/using-umbraco-7/72801-fixing-poor-performance-on-azure.

Specifying "Sync" will mean that the index that is stored in ~/App_Data/TEMP/ExamineIndexes/[IndexName] will get restored to the ASP.NET process's local temp folder (i.e. C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\vs\7a807fb2\7d5e4942\App_Data\TEMP\ExamineIndexes[IndexName], or z:\shared\sites\example.com\temp if you've changed ASP.NET's Compilation tempDirectory mentioned above).

ImageProcessor cache folders, ~/Config/imageprocessor/cache.config

Umbraco's ImageProcessor creates a lot of cache folders for uploaded images and media by default. To decrease the number of reads writes, and to decrease the number of directories the ASP.NET process has to go through, it's advised to limit the cache folders created.

Configure folderDepth="x" in in ~/Config/imageprocessor/cache.config (DiskCache key). For example folderDepth="2" to create a two level deep cache directory structure. The complete line becomes:

<cache
  trimCache="false"
  name="DiskCache"
  type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web"
  maxDays="365"
  browserMaxDays="7"
  folderDepth="2"
>

AllowSubDirConfig

This last one is tricky: AllowSubDirConfig(https://blogs.msdn.microsoft.com/sroun/2014/11/13/allowsubdirconfig-clarification/, https://blogs.msdn.microsoft.com/carmelop/2012/12/27/iis7s-performance-slower-than-iis6/) controls whether or not IIS searches for a web.config file in every subdirectory. If you have a lot of directories with a lot subdirectory's (for example the imageprocessor cache mentioned above), the ASP.NET process goes through every directory looking for web.config configuration settings. This takes a lot of time (relatively).

It is enabled by default. System administrators may choose to disable this setting using appcmd:

appcmd set vdir "/vdir.name:"example.com/ /allowSubDirConfig:false /commit

Migrate Umbrac SqlCe SDF database file to SQL Server database

If you want to be able to use Umbraco in a load-balancing hosting environment, you must have an SQL Server database for your site, and not the default SqlCe SDF database file. That doesn't scale. Here is a convert SqlCe to SQL Server post for you to follow.

Having your SqlCe database file converted to SQL Server has the great advantage you now can save your sessions in that database too! No more InProc sessions that are lost after application restarts (application pool recycles), but Out-of-Process sessions, properly saved in an SQL Server database.

Learn how to configure SQLServer sessionState for Umbraco.

Conclusion optimizing Umbraco 7 web performance

Out of the box, an Umbraco website runs pretty great. But the default configuration makes it read from and write to disk a lot. Too much if you'd ask me. That is unnecessary, particularly if you don't use some of the information provided, the log4net logs for example. This post gave you some pointers to optimize Umbraco performance, especially if you host dozens or hundreds sites on a single server or web-farm.

Let me know if this post helped you in optimizing your website! But be careful though, different optimization tips may be valid for different Umbraco versions. Always test first before putting your changes it into production.

More and more up-to-date information is in my How to optimize Umbraco 8 performance post.