Plausible proxy in Azure App Service

Mon, Nov 27, 2023 3-minute read

We use the excellent Plausible Analytics for tracking and analytics on the majority of our websites (including this one!)

This is in a direct and conscious alternative to Google Analytics. However, there is a known issue with all tracking scripts is that they can be blocked either by the browser or by plugins. Plausible are doing what they can to convince the maintainers of those products to stop blocking but on the basis that blocking can account for anywhere from 5% to 25% of tracking, it’s something that needs a more immediate fix. There used to be a workaround which meant hosting the script on a sub-domain (using DNS/CNAME) but apparently this is no longer reliable.

YAYRP

The method they advise is to proxy the script file, so that it looks like it was served from your domain.

Proxy6

In other words, instead of having something like

<script defer data-domain="yourdomain.com" src="https://plausible.io/js/script.js"></script>

in your HTML, you’d instead have

<script defer data-domain="yourdomain.com" src="/js/script.js"></script>

… but you do not have a local copy of that file - script.js is still pulled down from plausible.io.

They provide guides for lots of the major hosting providers and web software out there. Except Azure App Service, which is what we use for a number of our websites. Facepalm.

After reading about how a lot of the [networking in Azure was rearchitected])https://devblogs.microsoft.com/dotnet/bringing-kestrel-and-yarp-to-azure-app-services/) to use YARP - “yet another reverse proxy” - and then recently watching a dotnetconf session on it, I figured that YARP was definitely the way forward!

As it turns out, it was far, far easier than that, and doesn’t need YARP at all.

NARP

If you’ve worked with Apache or IIS in any administrative capacity then you’ll know about mod_rewrite which in IIS terms is referred to as Application Resource Routing. Unless you look carefully, you’d be forgiven for thinking this was not available in the cloudy version of IIS aka Azure App Service. However, you can enable it, with just a smidge of jiggery-pokery.

The solution requires a couple of things:

  1. A web.config (and some a rewrite rule)
  2. A magic file called applicationHost.xdt (which enables the rewrite engine, in Apache parlance)

The web.config is fairly simple:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="plausible" stopProcessing="false">
          <match url="js/script.js" />
          <action type="Rewrite" url="https://plausible.io/js/script.js" appendQueryString="false" logRewrittenUrl="false" />
        </rule>		
      </rules>
    </rewrite>   
  </system.webServer>
</configuration>

Nothing particularly odd going on here - the match url specifically matches a request for js/script.js and then explicitly rewrites that to the Plausible location. Easy.

The applicationHost.xdt enables the proxy functionality:

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false" />
  </system.webServer>
</configuration>

Winner winner chicken proxy

The sneaky bit is how you go about installing these files. You can just FTP them if you’re an old school barbarian.

Or, head over to the Kudu management thingo and do it in the browser… –> https://yourappname.scm.azurewebsites.net/DebugConsole

From there, click on site

Proxy1

and then drop your applicationHost.xdt in there (you can drag/drop!)

Proxy2

and go into wwwroot and drop the web.config in there

Proxy3

So instead of

Proxy4

if all is working you should see

Proxy5

i.e. the plausible script!

The above works for an Azure App Service with a Windows OS - steps will be a bit different for a Linux variant (not yet tested…)

A few things to keep in mind…

  1. if you already have a web.config then append your rules to it (don’t overwrite!)
  2. if already have a script.js then update the rewrites accordingly; just avoid using any words that make it look tracking-y / plausible-y
  3. you are very likely to be deploying your app service in a sensible way such as pipelines etc. so make sure to add the files to right place in your solution, so that they don’t get blown away next time you redeploy

Hope this helps… !