I’m writing this article next to the enchanting, lit-up Boston skyline, so I’ll try to stay focused.
When we are tasked with something new, the first place we usually start is Google. I had worked on CMS projects with separate authoring and delivery environments in the past, but I had never been tasked with setting them up. I knew it could be done, but how? Google led me to Umbraco documentation on load balancing – which was a great start. Load balancing distributes work across many servers and for our task we want to work with two or more servers. The load balancing documentation provided the multiple server customizations to be used in the Umbraco configuration file. After some trial and error it was time for Slack, which is a popular chat tool amongst Umbraco developers. I realized there were enough people that were curious about how I was setting things up, so Skrift article here I come.
Separation of environments involves having two or more environments, preferably each environment on a separate server. One environment contains the site with access to the Umbraco backoffice for authoring purposes. Another server contains the site purely for delivery of the content. The content will not be authored on the delivery environment. nor will the Umbraco backoffice will be accessible.
Why even have separate environments? Separation offers some stellar advantages. Security is important for every site, and if a delivery environment becomes compromised the content will still remain intact on its own server. This allows you to spin up a new delivery instance to publish to. Along with the fact that only one database is needed, there is an ability to publish content to multiple sites on different servers without having to re-enter or transfer content for each environment.
Security is important for every site, and if a delivery environment becomes compromised the content will still remain intact on its own server.
This is all great, Brittany! Where do I get started?
First things first, I’m writing based upon my experience while using Umbraco v. 7.2.8. Take note that distributed calls get an upgrade with v. 7.3.
-
Set up your servers, making sure you have admin privileges. All servers must be on the same network, part of the same domain, and be able to communicate with each other using HTTP protocol.
-
Configure IIS like normal, creating an authoring site on the authoring environment and a delivery site on the delivery environment. Here is a very important tip: For each site, even though they are different sites on different servers, they must have different ID values. Check this by going to the site’s Advanced Settings in IIS and looking for the ID field. If they are the same, like they were in my case, you need to change one of them.
-
Set up publishing profiles in Visual Studio for the new authoring and delivery environments. I’ll call these ProdDelivery and ProdAuthoring. *
* I also set up environments for staging delivery and authoring with their own staging database server. I developed the majority of the site in a local testing environment and towards the end of development when it was time to setup production, I tested everything in the separate staging environment first. Keeping the staging environments for future testing prior to hotfixes and releases is up to the client, but well worth it. -
Transfer your development database to the production database server. **
** Before transferring the database to the new server, a quick tip is to login to the Umbraco back office and add the ProdAuthoring IIS Domain. You should also add localhost for now, as this will allow you access to Umbraco on each server while setting up and testing.
-
Transform web.config and insert or replace the new database details for web.ProdDelivery.config and web.ProdAuthoring.config.
- Transform umbracoSettings.config and now the fun starts! In your ProdDelivery and ProdAuthoring umbracoSettings.config file, you’ll want to add a distributedCall section. It is very important that this section is included on all servers for communication. It will not work if it is only on one server.
<!-- Make sure enable is set to true -->
<distributedCall enable="true" xdt:Transform="Insert">
<!-- user 0 is admin -->
<user>0</user>
<!-- All servers will be listed here -->
<servers>
<!-- Authoring server always is listed first and
is also referred to as the Master server.
The serverName is the domain DNS name.
The server node's value is the IP address of the server or
the hostname of the site. -->
<server serverName="WEB-AUTH">IP.ADDRESS.GOES.HERE</server>
<!-- This server and any others after this are delivery servers
and also referred to as Slave servers. -->
<server serverName="WEB-DELIVERY">IP.ADDRESS.GOES.HERE</server>
</servers>
</distributedCall>
- Enable the call and insert or replace the distributedCall section depending on what’s in your base settings file. I tend to remove sections out of my base config file that I’m not using globally for all of my transformed configs and then insert any unique sections in the individual configs.
-
Users is set to 0 which is Umbraco Admin.
-
For the servers section, you’ll need to pay attention to the order in which the servers are listed and the details of each server. The first server listed is considered the Master server and any servers listed below are Slave servers. The Master server is always the Authoring server.
-
The serverName attribute is the domain DNS name.
-
I recommend using the IP address for the value of the server, but the hostname of the site will also work. For example, if my authoring site is http://www.auth.site.com, I would use www.auth.site.com in place of 172.17.1.9.
- Publish your solution to both ProdAuthoring and ProdDelivery.
Time to test!
Testing your setup is quick assuming everything is perfect, which let’s face it—when is it ever perfect on the first try? Go to the Umbraco back office of the authoring site, publish a change, and verify that change has also happened on the delivery site. You’ll want to disable any caching on the site while testing so you’re not waiting around to check for the changes....Personal experience has made me pull my hair out from 30 minute caching that I failed to disable. Once the separation has been tested thoroughly, disable the Umbraco back office for the delivery site. There are a few ways of achieving this, such as in the delivery server site’s configurations in IIS or in the ProdDelivery web.config file. I’ll direct you to a solution found at the digbyswift blog that directs the Umbraco login page to a 404. See a code example from the blog of this approach below.
<rule name="Restrict umbraco access" stopProcessing="true">
<match url="^umbraco/?.*"/>
<action type="CustomResponse" statusCode="404" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www.example.co.uk$"/>
<add input="{REQUEST_URI}" pattern="^umbraco/Surface/.*"
negate="true" ignoreCase="true" />
</conditions>
</rule>
This process may not be suitable for every site or client. There will be additional server costs based on how many servers you set up. At a minimum and a good place to start for the majority of sites is with one database server, one authoring server, and one delivery server. The upside of doing this in Umbraco is that unlike other CMSes that have license costs per server or instance, Umbraco licenses are free for one and free for all!
It’s load balancing without the load balancer. We just need to communicate to the delivery server(s) when there is a change.
When you first approach this beast, it seems like an arduous process, but if you follow these steps it should be smooth sailing. It’s load balancing without the load balancer. We just need to communicate to the delivery server(s) when there is a change on the authoring environment. Hello Distributed Calls and Cache Refresher. When distributed calls are enabled and servers are defined, the Umbraco core will call the cache refresher for each remote server. If you’re interested in digging deeper, I’d start with Umbraco.Core/Sync/DatabaseServerMessenger.cs in the NotifyRefreshers method. It’s passed a json of instructions as to which cache refresh type should be called, such as RefreshAll, RefreshById(s), and RemoveById.
Umbraco has great documentation on Load Balancing which provides information on setting your system up in separate environments. If you’re working in an environment prior to 7.3 refer to Umbraco’s Traditional Load Balancing guide, and for 7.3 onwards refer to the Flexible Load Balancing guide. When separating your environments you’ll always have the option to add a load balancer in the future if needed or desired.
I’d love to hear thoughts from others that have set up their sites in a decoupled fashion or those that are heading in that direction. You can find me on twitter @RadianceBox. I’ll tweet you back as long as my fingers haven’t frozen off in the wintery bluster of Boston.