Static websites in Azure Storage

Table of Contents

Introduction

If you are looking to a host website that contains static content with client-side scripting, ie: JavaScript, HTML/HTML5, AJAX, etc.., you can use an Azure Storage account with the Static website feature enabled. The key advantages to Static over Dynamic websites are:

  • Utilizing inexpensive cloud solutions, like Azure Storage accountsAmazon S3Google Cloud, etc...
  • Depending on the particular use cases, these services are much more cost effective in comparison to traditional hosting services
  • Zero maintenance as there is no Operating System or Content Management System to secure, patch or manage

Static websites are simple by design and serve well as informational and blog sites. However, both Static and Dynamic websites have their use cases and deciding on which method to use would be based on the sites requirements. 
 
This post focuses on the benefits to using Static websites with Azure Storage accounts, covering how to:

There are a number of recommended Static CMS options, though my personal preference is Publii. I won't labor these options as choosing a CMS is ultimately a personal choice based on look/feel, features, support or a combination of all. 

The advantages to using Azure Storage accounts are:

  • Cost is very cheap cost per GB
  • The ability to use a custom domain
  • Supports both HTTP and HTTPS
  • Basic firewall to only permit certain IP's or ranges
  • Includes a native Storage Explorer to perform basic file (blob) and folder (container) management
  • Integrate with a Content Delivery Network (CDN) + Endpoint for extra functionality 

If you want either an apex or sub-domain with an SSL certificate, you will need a CDN. There are other benefits to using a CDN, including:

  • Creating a sub-domain with an SSL certificate that is auto-renewed by DigiCert
  • Geo-filtering, ie: blacklisting/whitelisting countries
  • Caching, compression and optimization options
  • Engine rules, ie: HTTPS redirect

Naturally, there are costs associated to using a CDN, which differ based on zones, data content served and CDN plans. Best to consider your requirements and current CDN options before choosing one. If you site is lite and has fewer visitors, the total costs should still be relatively cheaper in comparison to traditional hosting methods.

Create a sub-domain website (without SSL)

Enabling the Static website feature on an existing Storage account will enable HTTPS (SSL) by default. However, will end up with a rather unusual address, known as the endpoint address, ie: 

https://magrintest.z13.web.core.windows.net/

This is fine if you don't require a custom domain or just evaluating this feature. 

For the purpose of this exercise, we will create a sub-domain without SSL by disabling HTTPS. Though this set up is rather simple and doesn't require a CDN, it is rather limited and data in transit is unsecure.

Create an Azure Storage Account
  • In the Azure Portal, navigate to Storage accounts > [+ Add] to create a Storage account
  • Location: Choose a region that is geographical closer to you or cheaper per GB, it's up to you
  • Performance: Standard
  • Secure transfer: Disabled
  • Access tier: Cool 
  • Replication: LRS
  • Disable the rest of the features as they are not needed
  • Navigate to the 'Static website' blade under [Settings] of the Storage account and toggle [Enabled] under the 'Static website' and select [Save]. Note down the 'Primary endpoint address', ie: 

    https://magrintest.z13.web.core.windows.net

  • Specify the index document name, ie: index.html and select [Save]
  • Select 'All networks' within the 'Firewalls and virtual networks' blade under [Settings]
  • Under [Blob services] select 'Containers' > and within the $web container, select [Change access level] and set it to 'Container (anonymous read access for containers and blobs)'
Create a Custom Domain

Create a CNAME record with your DNS provider for the sub-domain to the account's endpoint address:

In the Storage account, select 'Custom domain' blade under [Blob service], in the 'Domain name' field, enter the sub-domain address, test.magrin.one, and select [Save].

Create the Index Document

Using your favourite text editor, create an index document and save it as index.html, ie:

<html>
<title>Magrin Test</title>
<body>
<p>Hello World!</p>
</body>
</html>

In the Storage account, navigate to the 'Containers' blade under [Blob service]. 
Within the $web container, select [Upload] to copy the index.html file. 

Testing the site

Open a browser and go to the sub-domain's address, ie: 

http://test.magrin.one

If you get an error, check the firewall of the Storage account, access to the $web container and the whether the index document has any syntax errors. 

Create a sub-domain website

Unlike the previous set up, creating sub-domain with a trusted SSL using a Storage account does require a CDN. In this exercise, we will create a Storage account, a CDN Profile and a CDN Endpoint, a custom sub-domain and request an SSL certificate with auto-renewal. 

Create an Azure Storage Account
  • Log into the Azure Portal with the appropriate role, navigate to Storage accounts > [+ Add] to create a Storage account and select the following options:
  • Location: Doesn't matter really, though I created mine in the same region as the CDN (West US), but this isn't required
  • Performance: Standard
  • Secure transfer: Enabled
  • Access tier: Cool 
  • Replication: LRS
  • Disable the rest of the features as they are not needed

Allow a few moments for the Storage account to be created. Once the deployment completes, we will need to note a couple of values and update some settings.

  • To enable the Static website feature:
    • Navigate to the 'Static website' blade under [Settings] of the Storage account and toggle [Enabled] under the 'Static website' and select [Save]. Note down the 'Primary endpoint address', ie: 

      https://magrinwww.z22.web.core.windows.net 

    • Specify the index document name, ie: index.html and select [Save]
    • When enabling the Static website feature, a container called $web is created; this is where static web content for your site will reside
    • For testing, create and upload a basic index document called index.html into the $web folder using the 'Storage Explorer (preview) blade

  • To allow anonymous access to the Storage account:
    • In the 'Firewalls and virtual networks' blade under [Settings], select 'All networks' and [Save]
    • In the 'Containers' blade under [Blob services] and within the $web container, select [Change access level] and set it to 'Container (anonymous read access for containers and blobs)' and [OK]

Note: This provides read access to all files (blobs) and folders (containers) within the $web container only and not to other containers at the root level of the Storage account.

  • Test the Static website feature:
    • In a browser, navigate to the endpoint address of the Storage account, ie: 

      https://magrinwww.z22.web.core.windows.net

      The basic index document should be served. If you encounter an error, validate that the firewall and access levels to the $web container have been configured correctly before proceeding.
Create a Content Delivery Network (CDN)

In the Azure Portal, select the hover over > [Create a resource], search for CDN and select 'CDN / Microsoft' > [Create]. Give your CDN a meaningful and globally unique name, select the subscription, resource group and importantly the 'Pricing tier'. For this set up, select 'Microsoft Standard' and [Create]. The deployment of the CDN can take several minutes to complete.

Create a CDN Endpoint 

Once the CDN has been deployed, we will need an additional component called an Endpoint that manages the actual web content, ie: caching, compression, custom domain, optimization, rules engine, etc... In the Azure Portal, search or navigate to 'CDN profiles' and select [+ Endpoint] to create an Endpoint.

In the 'Add an endpoint' set up, specify a globally unique name that relates to the website that you are creating, in the 'Origin type' drop down, select 'Custom origin', in the 'Origin hostname', enter the endpoint address of the Storage account that you created earlier without the prepending protocol, ie:

magrinwww.z22.web.core.windows.net

Leave the rest of the options and select [Add] to create the Endpoint, allowing a few moments for the deployment to complete. Test the Endpoint by navigate to its hostname address in a browser, ie:

https://magrinwww.azureedge.net

The basic index document should be served, validating that the CDN Endpoint is working. If you get an error, it's likely the Endpoint is still provisioning in the background and may take several minutes more to set up. 

Create a Custom Domain

Before we can create a custom sub-domain, we will need to create a CNAME record to verify domain ownership. Whether you use Azure DNS or another DNS provider, create the following record for the www sub-domain:

  • Type: CNAME
  • Source: cdnverify.www.magrin.one
  • Destination: cdnverify.magrinwww.azureedge.net
  • TTL: 60 seconds (to rapidly propagate the record)

Navigate back to the CDN Endpoint > under 'Settings', select the 'Custom domains' blade, select [+ Custom domain]. In the 'Custom hostname' field, enter the sub-domain address, ie: www.magrin.one and select [Add] to complete the set up.

Create a SSL Certificate

We will need to create another CNAME record for the actual sub-domain and SSL certificate creation. In this set up, the CDN will manage our SSL certificate and auto-renew it annually, taking the hassle out of certificate management. Create the following record for the sub-domain to the Endpoint hostname:

  • Type: CNAME
  • Source: www.magrin.one
  • Destination: magrinwww.azureedge.net
  • TTL: 60 seconds (to rapidly propagate the record)

Select the Endpoint > 'Overview' blade and under 'Custom domains', select the previously created custom domain, toggle to [On] under 'Configure / Custom domain HTTPS' and select 'CDN managed'. 
There are four steps to this process, which entails submitting your SSL request, verifying the domain, creating and applying the certificate to the Endpoint. 
This happens automatically and can take a few hours or up to a day to complete. You can revisit this section to view the status.
When the certificate has been deployed, open a browser and navigate to the custom sub-domain, ie: https://www.magrin.one - the basic index document should open. Finally, replace the basic index document with the static content of your website.

Create a HTTPS Redirect Rule

It's handy to have a HTTPS redirect rule should visitors lazily enter www.magrin.one; the rule will automatically redirect them to https://www.magrin.one. Read more on creating rule here.
To create a HTTPS redirect rule, select the Endpoint and under [Settings], select the 'Rules engine' blade > [+ Add rule]. Name the rule, select [+ Add condition] > 'Request protocol'. For the 'Operator', select 'HTTP' in the drop down. 
Select [+ Add action] > 'URL redirect'. For the 'Type', select 'Found (302)' in the drop down and for the 'Protocol', select 'HTTPS' and complete by selecting [Save]. 

Create an apex domain website

Note: At the time of writing for an apex domain, you needed to bring-your-own trusted certificate from a certificate provider and have a Azure Key vault to store the certificate in. Read more here.

Another way I worked on was redirecting visitors going to the apex domain to the sub-domain, ie: magrin.one > www.magrin.one. As much as I wanted the apex domain as the primary site, I didn't want manage the certificate renewal manually. 

I initially created a sub-domain website with an SSL certificate earlier, then set up an apex domain website (magrin.one), redirecting visitors to the sub-domain (https://www.magrin.one). Makes sense? I'll explain more in detail. The mechanics behind this set up requires:

  • Two Storage accounts:
    • One for the apex domain website, which uses JavaScript embedded in the index document to redirect users to the sub-domain
    • The other Storage account hosting the sub-domain website; this has the certificate managed by the CDN as created earlier
  • One CDN Profile with two Endpoints, one for each domain
  • A DNS Zone (Any DNS provider will do, though I use Azure DNS)
Create an Azure Storage Account
  • In the Azure Portal, navigate to Storage accounts > [+ Add] to create a Storage account
  • Location: Doesn't matter really, though I created mine in the same region as the CDN (West US), but this isn't required
  • Performance: Standard
  • Secure transfer: Disabled

Important: HTTPS must be disabled as this will prevent the redirect from working if 'Secure transfer' is enabled. When visitors go to magrin.one, JavaScript embedded in the index document of the apex website site will redirect them to the sub-domain website that has the SSL certificate.

  • Access tier: Cool 
  • Replication: LRS
  • Disable the rest of the features as they are not needed
  • Navigate to the 'Static website' blade under [Settings] of the Storage account and toggle [Enabled] under the 'Static website' and select [Save]. Note down the 'Primary endpoint address', ie: 

    https://magrinapex.z22.web.core.windows.net

  • Specify the index document name, ie: index.html and select [Save]
  • In the 'Firewalls and virtual networks' blade under [Settings], select 'All networks' and [Save]
  • In the 'Containers' blade under [Blob services] and within the $web container, select [Change access level] and set it to 'Container (anonymous read access for containers and blobs)' and [OK]
Create the Index Document

Using your favorite text editor, create an index document and embed the following JavaScript window.location.replace code for the redirect function, ie:

<html>
<title>Magrin One</title>
<link rel='icon' href='favicon.png' type='image/x-icon'/>
<body>
    <body bgcolor="1a628f"></body>
</body>
<script>window.location.replace("https://www.magrin.one")</script>
</html>

In my example, I added the same favicon and background color to match my main website, but this is totally optional. Save this file as index.html
Back to the Storage account, navigate to the 'Containers' blade under [Blob service]. 
Within the $web container, select [Upload] to copy the index.html and associated files. 

Test the Apex Static Website

Open your browser and test whether the redirect works by going to the apex's website's address, ie: 

https://magrinapex.z22.web.core.windows.net/

If in doubt, check the firewall of the Storage account, access to the $web container and whether the index document has any syntax errors. 

Create a CDN Endpoint

Create an Endpoint by giving it a meaningful but globally unique name, specify the origin type as 'Custom origin' and use the 'Primary endpoint address' of the apex Storage account, without the prepending https://, ie: 

magrinapex.z22.web.core.windows.net

Leave all other options and select [Save]. This will create an Endpoint hostname address that is mapped to the Storage account's address, ie:

https://magrinapex.azureedge.net

Test by going to opening the Endpoint hostname in your browser, which should continue to redirect to the sub-domain.

Create a Custom Domain

Unlike other DNS providers, Azure doesn't allow creating a CNAME record to an apex domain. There is two ways around this; either use another DNS provider or if you use Azure DNS, create an A record to the CDN Endpoint using an Alias record set, which creates an A record to the CDN Endpoint's IP address. 

For this step, we will need to create two DNS records; a CNAME record to verify domain ownership and an A record to map the apex domain to its associated CDN Endpoint. 
To validate ownership of the domain, Microsoft accepts different verification options, ie: email, editing a HTML file or creating a DNS record. In this example, I will demonstrate the latter. To begin, create the CNAME record to verify the domain:

  • Type: CNAME
  • Name: cdnverify
  • TTL: 60 seconds (or greater)
  • Alias: cdnverify.magrinapex.azureedge.net

Now create an A record for the apex domain to the CDN Endpoint:

  • Name: Leave blank
  • Type: A
  • Alias record set: Yes
  • Alias type: Azure resource
  • Select your subscription
  • Azure resource: Azure CDN > CDN Profile/Endpoint name
  • TTL: 60 seconds (or greater)

To complete creating a custom domain, navigate to the CDN Profile > Endpoint for this site, select 'Custom domains' under [Setting] and under the 'Custom domain' field, enter the apex domain, ie: magrin.one, which will validate the DNS records above and select [Add] to complete this step.

Testing the Apex to Sub-Domain Redirect

To ensure the custom domain is functional, query the apex domain DNS records, ie:

nslookup magrin.one
Server: one.one.one.one
Address: 1.1.1.1

Non-authoritative answer:
Name: magrin.one
Address: 13.107.246.10

Finally, open a browser and go to the apex domain, which should immediately redirect to the sub-domain website.

Purging a CDN Endpoint

Whenever you synchronize or update new content for your Static website, you can purge the CDN Endpoint to trigger an immediate flush of cached copies of old content from all edge point-of-presence (POP) locations.
On a Microsoft Standard CDN Profile, the default cache time-to-live is two days, in which the POP's are flushed and any requests need to be re-cached.

To manually purge the CDN Endpoint:

  1. Navigate to 'CDN Profiles' and select the CDN Endpoint under [Overview]
  2. Select [Purge], tick 'Purge all' and select [Purge] below.


This will take a few moments to purge all edge POP's.