Run imgproxy container on Azure App Service with Front Door CDN

Taking a look at how to run your own imgproxy instance on Azure.

A while back I posted on making imgproxy work with an Optimizely CMS app but it wasn't until now that I had a fitting case to use it.

I recommend first to read the above post, to see how to run locally and how to use C# to construct image URLs.

To keep it simple I chose to use Azure App Service for this hosting scenario. This is the log of the work:

Add new resource, search and pick Web App for Containers.

Set tier to Linux Basic (B1).

When seeing options for registry and image; select Docker Hub and set image/tag to darthsim/imgproxy:v3.24-amd64.

Edit Environment variables, my advanced edit looks like this to be able to use some of the code from the first blog post:

[
    {
      "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
      "value": "",
      "slotSetting": false
    },
    {
      "name": "DOCKER_REGISTRY_SERVER_URL",
      "value": "https://index.docker.io",
      "slotSetting": false
    },
    {
      "name": "DOCKER_REGISTRY_SERVER_USERNAME",
      "value": "",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_ALLOWED_SOURCES",
      "value": "https://your-images-served-from-here.com/",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_ENABLE_AVIF_DETECTION",
      "value": "true",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_ENABLE_WEBP_DETECTION",
      "value": "true",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_ENFORCE_AVIF",
      "value": "true",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_ENFORCE_WEBP",
      "value": "true",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_FORMAT_QUALITY",
      "value": "jpeg=95,avif=75,webp=85",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_KEY",
      "value": "333636303563363065726464",
      "slotSetting": false
    },
    {
      "name": "IMGPROXY_SALT",
      "value": "33393737643963656473",
      "slotSetting": false
    },
    {
      "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
      "value": "false",
      "slotSetting": false
    }
]

Compared to the first blog post you can see that I here skip IMGPROXY_SECRET and instead have IMGPROXY_ALLOWED_SOURCES set.

Restart App after editing.

App Service should detect that container is using port 8080 and if you use the app service *.azurewebsites.net URL you should now see a page with the imgproxy logo.

To try it out you can use some code from the first post and use the *.azurewebsites.net URL instead of http://localhost:8080 and pull an image from the URL you set as IMGPROXY_ALLOWED_SOURCES.

For Optimizely CMS; add the EPiServer.CdnSupport project and set OverrideHost to the *.azurewebsites.net URL.

I would also use this project's URL creation method as the place to customize the URLs for imgproxy.

Testing caching of images with Azure Front Door

If you want a code free way to get some caching of transformed images; go to Networking and add a Front Door resource under Optional inbound services.

Check that your imgproxy instance works through the *.azurefd.net name.

Note that the following request headers don't get forwarded to the origin when caching is enabled:

  • Content-Length
  • Transfer-Encoding
  • Accept
  • Accept-Charset
  • Accept-Language

This complicates things and really makes Front Door a poor choice for imgproxy, that is made to use identical URLs and check the Accept header value to send the best accepted format.

If you stop here with the current configuration, you will get image URLs cached in Front Door's CDN, but every response will be AVIF.

HTTP/2 200
date: Mon, 06 May 2024 07:00:54 GMT
content-type: image/avif
content-length: 5273
cache-control: max-age=31536000, public
vary: Accept
content-security-policy: script-src 'none'
x-request-id: WwOeoxNYg0g-JeQGnU4eA
content-disposition: inline; filename="image.avif"
x-azure-ref: 20240506T072354Z-1654dd6c8cbprv5mr5txk6yyen00000000pg000000002c5t
x-fd-int-roxy-purgeid: 3
x-cache: TCP_HIT
accept-ranges: bytes

A setup that sort of works for at least sending WEBP if not accepting AVIF, but opens up an attack surface, is to add a rule that says: If Accept header does not contain "image/avif", override Origin group and set Caching to Disabled.

This rule can also be duplicated for JPG instead of WEBP and you will get responses straight off imgproxy where the Accept header is evaluated.

Please, send information if you have found a better way of configuring Front Door. I settled for now to keep using Front Door but only get AVIF since that browser support is getting really good.

Moving forward I would probably replace Front Door with a more configurable caching reverse proxy resource.

Comments?

Published and tagged with these categories: Optimizely, CMS, ASP.NET, Azure