Are you planning to set up the multi-site solution in
Sitecore, which needs to configure on Azure WAF level?

The Multi-site solution in Sitecore is a straight forward
process and needs some entry in the web.config to resolve the multiple
websites, for more information about Sitecore multi-site setup, you can follow
this blog:

https://doc.sitecore.com/developers/81/sitecore-experience-platform/en/configure-multiple-managed-websites.html

If you are not using AZURE WAF, then it’s straight forward
process, you need to add the multiple domain mapping on your Azure CD – App Services

Steps:

  1. Go to the App service – CD
  2. Add the custom domain tab on the left side
  3. Add the custom domain mapping
  4. Add the CNAME to the Azure CD URL




Once you did the above configuration, then we need to add the
entry in the Sitecore config file with the site name, and then automatically the multi-site domain will be resolved.

But the real challenge comes, when we are configuring the
WAF with Azure PaaS, because now all the requests will come from WAF level, and
the custom domain needs to configure/Map on the Azure WAF level,
In this case, a request is coming on WAF first then, CD (App Services) then the web.config( where the domain is resolving in Sitecore)

We have setup multi-domain on Azure WAF using this Microsoft
blog:
https://docs.microsoft.com/en-us/azure/application-gateway/create-multiple-sites-portal
But the problem is – a custom domain is not passing from
Azure WAF to CD server(web apps) that’s the reason it’s not resolving the
multi-site domain.
Below is the configuration we did on WAF level:
  1. Azure VNet setup
  2. Azure WAF setup
  3. Domain level changes
  4. WAF – configuring multi-site


Solution:

We did multiple tries to configure the custom domain on WAF
level, but somehow not able to resolve the domain on Sitecore config level,
then finally we thought about the customization in the Sitecore pipeline:

All the requests in Sitecore are going through the specific
pipeline before resolving the Request, so we had to figure out which is the
main pipeline where a multi-site domain is resolving, after doing some research
we got to know that “SiteResolver” in HttpBegin Pipeline is the right place for
this customization.

So now the challenge is to know some identifier of
the domain in the headers so that we can resolve the site based on the same header key, so after debugging the headers parameters we found one unique the identifier in below header parameter:

X-ORIGINAL-HOST

In this parameter, the domain is coming from WAF, so we put
the condition based on the parameter as below:

Below is the code for this logic:

//for custom checking the site domain and resolving the
domain

            foreach (SiteInfo info in this.SiteContextFactory.GetSites())
            {
                var originalHost = args.HttpContext.Request.Headers["X-ORIGINAL-HOST"];
                if (!string.IsNullOrEmpty(originalHost) && info.HostName == originalHost)
                {
                    siteContext = new SiteContext(info);
                }
            }

           

Also, below is the complete class code for the same
implementation; we have created a custom pipeline called “customSiteResolver.”

public class CustomSiteResolver : SiteResolver
    {
        public CustomSiteResolver() : this(ServiceLocator.ServiceProvider.GetRequiredService<BaseSiteContextFactory>())
        {
        }
        public CustomSiteResolver(BaseSiteContextFactory siteContextFactory) : base(siteContextFactory)
        {
        }
        protected CustomSiteResolver(BaseSiteContextFactory siteContextFactory, bool enableSiteConfigFiles) : base(siteContextFactory, enableSiteConfigFiles)
        {
        }
        public override void Process(HttpRequestArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            SiteContext site = CustomResolveSiteContext(args);
            this.UpdatePaths(args, site);
            this.SetSiteToRequestContext(site);
        }

        protected virtual SiteContext CustomResolveSiteContext(HttpRequestArgs args)
        {
            SiteContext siteContext = null;
            string queryString = this.GetQueryString(this.SiteQueryStringKey, args);
            if (queryString.Length > 0)
            {
                siteContext = this.SiteContextFactory.GetSiteContext(queryString);
                Assert.IsNotNull(siteContext, string.Concat("Site from query string was not found: ", queryString));
                return siteContext;
            }
            if (this.EnableSiteConfigFiles)
            {
                string str = this.ExtractSiteConfigPathForRequestedDirectory(args);
                if (!string.IsNullOrEmpty(str))
                {
                    siteContext = this.SiteContextFactory.GetSiteContextFromFile(str);
                    Assert.IsNotNull(siteContext, string.Concat("Site from site.config was not found: ", str));
                    return siteContext;
                }
            }
            //for custom checking the site domain and resolving the domain
            foreach (SiteInfo info in this.SiteContextFactory.GetSites())
            {
                var originalHost = args.HttpContext.Request.Headers["X-ORIGINAL-HOST"];
                if (!string.IsNullOrEmpty(originalHost) && info.HostName == originalHost)
                {
                    siteContext = new SiteContext(info);
                }
            }
            if (siteContext == null)
            {
                Uri requestUrl = args.RequestUrl;
                siteContext = this.SiteContextFactory.GetSiteContext(requestUrl.Host, args.Url.FilePath, requestUrl.Port);
            }
            return siteContext;
        }

    }

Below is the configuration to patch the above code in the pipeline

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <httpRequestBegin>
        <processor type="CustomApp.Foundation.CMS.Pipelines.CustomSiteResolver, CustomApp.Foundation.CMS" patch:instead="processor[@type='Sitecore.Pipelines.HttpRequest.SiteResolver, Sitecore.Kernel']" />
      </httpRequestBegin>
    </pipelines>
  </sitecore>
</configuration>

Note: All custom domain will read from the standard Sitecore multi-website config only.
  
I hope this article will help you.
Happy Sitecoring

2 Replies to “Setup Sitecore Multi-Domain Solution on Azure WAF level”

  1. This information is really awesome thanks for sharing most valuable information.
    Sitecore Online Training
    Sitecore Training in Hyderabad

Leave a Reply

Your email address will not be published. Required fields are marked *