• Published
  • 4 min

Reverse proxy in DXP for legacy systems

some code example to illustrate

How to configure a reverse proxy in DXP (Azure website) with manipulated host request for legacy systems

We recently had a client that needed to expose a legacy system that only responded to the production host (ex. www.productionsite.com) used by the website on DXP.

To achieve this we needed to implement a reverse proxy using Application Request Routing and URL Rewrite that would allow the legacy path (www.productionsite.com/legacysystempath) to be displayed on the site.


Activate the proxy functionality in the Azure website

Add the file applicationHost.xdt to your repo. It does not need to be included in your Visual studio project.

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
    <proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="true" reverseRewriteHostInResponseHeaders="false" />
</system.webServer>
<location path="%XDT_SITENAME%" xdt:Locator="Match(path)">
    <system.webServer xdt:Transform="InsertIfMissing">
        <rewrite xdt:Transform="InsertIfMissing">
            <allowedServerVariables xdt:Transform="InsertIfMissing" >
                <add name="HTTP_X_USE_HTTPS"                xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
                <add name="HTTP_X_ORIGINAL_HOST"            xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
                <add name="HTTP_X_UNPROXIED_URL"            xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
                <add name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
                <add name="HTTP_ACCEPT_ENCODING"            xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
                <add name="HTTP_HOST"                       xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
                <add name="HTTP_URL"                       	xdt:Transform="InsertIfMissing" xdt:Locator="Match(name)" />
            </allowedServerVariables>
        </rewrite>
    </system.webServer>            
</location>
</configuration>


Add your rewrite rules for the system to be proxied to web.config

In our case the legacy system only responded to our production URL so we needed to manipulate the host in the request to the legacy system. The system itself had a separate host that was mapped to the actual server but the application on said server was not bound to the server host.

<system.webServer>
    <rewrite>
        <rules>
            <rule name="ProxyFureg" stopProcessing="true">
                <match url="^legacysystempath/(.*)" />
                <action type="Rewrite" url="http://legacyserver:8081/legacysystempath/{R:1}" />
                <serverVariables>
                    <set name="HTTP_URL" value="http://www.productionsite.se/legacysystempath/{R:1}" replace="true"/> 
                    <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" /> 
                    <set name="HTTP_X_ORIGINAL_HOST" value="www.productionsite.se" />
                    <set name="HTTP_HOST" value="www.productionsite.se"  replace="true"/>
                    <set name="HTTP_ACCEPT_ENCODING" value="" />
                </serverVariables>
            </rule>
        </rules>
    </rewrite>
</system.webServer>

Note that we added additional rewrite rules to handle any additional resources of the legacy system required such as stylesheet and script paths.

Make sure that the applicationHost.xdt is added to the nuget package when Deploying

In Azure website the applicationHost.xdt file needs to be outside of the wwwroot folder (in our case /site).
Our build process is based on Azure DevOps pipelines and the Epinova DXP Deployment extension (Here is the start of our Blog posts detailing more about our deployment process).
To achieve the final step we needed to add the following task to our pipeline YAML file (azure-pipeline.yml that is included in the root of our repo).

- task: VSBuild@1
  displayName: 'Build solution $(solution)'
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:Configuration=Release;MvcBuildViews=true;DeployOnBuild=True;DeployDefaultTarget=WebPublish;WebPublishMethod=FileSystem;PublishProvider=FileSystem;LastUsedBuildConfiguration=Release;ExcludeApp_Data=False;publishUrl=$(Agent.TempDirectory)/SitePackageContent/wwwroot;DeleteExistingFiles=False'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

- task: CopyFiles@2
  displayName: 'Copy applicationHost.xdt to Site folder'
  inputs:
    SourceFolder: $(Build.SourcesDirectory)
    Contents: applicationHost.xdt
    TargetFolder: $(Agent.TempDirectory)/SitePackageContent
    OverWrite: true
  continueOnError: true

Note that the MSBuild step outputs to /SitePackageContent/wwwroot while we copy the file to /SitePackageContent

Result

The path www.productionsite.com/legacysystempath and it's dependencies such as JS & CSS now show the legacy system thanks to the reverse proxy rules even though it's only accessibly through a hostname that the legacy system knows nothing about.