Static website hosting on Azure

I’ve previously discussed how to host a static website in a cheap yet reliable way that can still easily scale so I was excited to see that Azure made the static website for storage generally available.
https://azure.microsoft.com/en-us/blog/static-websites-on-azure-storage-now-generally-available/

Even though I liked the previous solution, using an Azure Function proxy, it did have some drawbacks like cold start time on a rarely touched site (who wants to wait up to 6 seconds for the first byte?) and also the local presence is not optimal up here in Sweden so even the fastest request takes from about 30 ms.

Using the new static website feature for storage you get faster and more consistent loading times.
Even though it is possible to add a custom domain directly to your storage I would not recommend it since it lacks the possibility to add an SSL certificate and if you are going to build an app, that’s essential.
Encryption can, however, be achieved using a CDN on top of your storage and Microsoft even have an excellent guide for that:
https://docs.microsoft.com/en-gb/azure/storage/blobs/storage-blob-static-website-host (2 parts).

So far everything looks great, but I ran into some questions along the way that needed to be solved.

1. The naked domain

The first question arose when I wanted to point the custom apex (naked) domain to the site (Eg https://bodhiapp.io instead of https://www.bodhiapp.io). Since the custom domain is configured using a CNAME pointer this is unfortunately not doable. Azure is not to blame for this, it’s just the way DNS works.
https://medium.freecodecamp.org/why-cant-a-domain-s-root-be-a-cname-8cbab38e5f5c
For me, it’s not sufficient to only use a subdomain like www, if I cannot also have a redirect from the naked domain, and if I cannot point to the naked domain, I cannot make a redirect either, right?
To solve this I used the good old Azure function proxy again. Yes, we are going to have the same issues as the previous solution but it is just for the redirect so it should be manageable.
The setup is pretty simple, follow a guide for how to set up an Azure Function on a Consumption Plan and add your custom domain and DNS apex A-pointer to it (you can use A-pointer here since it has a public IP).
For your new proxy add one simple rule:
Name: redirect (or whatever you like)
Route template: /{*restOfPath}
All methods and no backend URL.
Expand Response override and enter status code 301 (permanently moved) and Add Header:
name: Location
value: https://www.yoursite.com{restOfPath}

Configuring the redirect proxy

The subdomain is, of course, imperative to add here in the redirect location.
I use 301 (permanently moved) to ensure that search engines skip any previously indexed pages on apex level this and only indexes your new subdomain in the future.
If you are having issues with cold start times for the proxy you may want to use the ping or timer trick (https://liftcodeplay.com/2017/12/19/strategies-for-improving-eliminating-azure-functions-cold-starts/) for keeping it warm, for this scenario it is however only a backup strategy so it may be unnecessary.

2. Caching

My second concern is that a CDN on top of my pages, of course, is going to cache them — because that’s what CDN:s do.
The default caching time the CDN’s are 7 days and that’s not really what you want if you have continuous delivery and a fast build pipeline.
The various options for standard CDN seem to partially respect Cache-control headers from origin or expiration meta in HTML.
For the Microsoft option, I was not able to make pages reload from origin any faster than five minutes and the control was rather blunt so after some testing, I decided on the Standard Verizon option setting up the CDN.
For the Verizon option, I can control the caching more fine-grained and don’t have to rely upon setting headers on the origin assets.
https://docs.microsoft.com/en-us/azure/cdn/cdn-manage-expiration-of-blob-content
Even though it is possible to make the CDN reload and asset from origin every single time it is touched this would not be my first choice since it, of course, makes loading slower.
I decided for myself that a few minutes cache for the index-page is ok, and other assets can be cached longer.
Typically in a SPA, your build will generate version numbers for JS and CSS assets so it should no problem with long caching as long as your index page is reloaded.
For my endpoint I set up Global caching rules with Caching behavior: Override, expiration duration 3 minutes (or whatever you like) and Ignore query strings. The last option I selected because the intended use for the static site was to host a SPA so most requests will just go to the index page anyway.
To this, I added a Custom caching rule with condition Path, with value /assets/* selected behavior Set if missing and configured it to 1-day cache.

I should probably point out that this requires that you actually have your origin assets in a folder named assets for it to work.

That’s it! Now we have a fast secured scaling static site with apex redirection and great local presence worldwide that is still very cheap when the traffic is low. If you have found a more efficient way to do this — please let me know!
Have fun!