Azure Static Web App Services

Cheap, Easy, Scaled, Static Web Hosting on Azure

Seann Hicks

Seann Hicks

Sunday, May 24, 2020

Introducing Azure Static Website App Services

I just attended the Microsoft Build 2020 conference (May 19, 20). It was a fully virtual conference, and overall it went very well.

One Build 2020 highlight in the Azure Cloud space was the Static Web Application Service, a new App service that allows you to host a single page app (SPA) built on Angular, React or Vue or a Static Web Site with and Azure functions API.  This service also allows you to host Static Web Sites built on Gatsby, Hugo or VuePress.  Jekyll also works, however the Microsoft doc does not cover it.

Azure Static Web App Services seem to be a direct competitor for services like netlify or Vercel (Formerly Zeit).  These are free hosting services (for blogs) with integrated GitHub workflows that allow you to host a blog written with a static website tool like Jekyll or Hugo.

Azure Static Web Apps are a great contender for static web sites and SPAs.  Some features include:

I have a deployed a few flavors of static sites as Azure Static Web Sites and overall I'm impressed.  This article includes some of my early experiments and findings.

Microsoft provides guides for deploying these types of sites with starter code you can pull into your project.

Free SSL Certificate

Yay! Buying and managing SSL certificates is a hassle I can do without.  Fortunately Static Web Apps handle this for you. When you bind a custom domain to your site Azure creates a certificate and binds it automatically. Certificates are provided by Geotrust, are encrypted with 2048 bit keys and are valid for 6 months (and I guess are auto-renewed on expiry). I ran a Qualys SSL check on the certificate, it supports TLS 1.2 (not 1.3 and nothing earlier) and is a good quality cert. Results are below.

Azure Static Web App Geotrust Certificate Audit

Creating a Vanilla Azure Static Website

My first experiment was to deploy a basic fully handcrafted single page site with simple sass driven css.  I have the pageboy.ca domain which I used for this site.

Static web apps integrate with GitHub (Azure DevOps is not an option). Before you create a Static Web App you'll need a web site project checked into GitHub.

I had a basic one page site for one of my domains, pageboy.ca, so this was a great starter candidate. It has some simple Sass based styles and an index.html page. I use the npm sass compiler, so I already had a package.json file.  NodeJs is not necessary however, just leave the app artifact location field blank to skip a build step.

GitHub Actions

When you setup your Static Website Azure will create a GitHub action and register an access key to connect from GitHub to Azure. This action runs a build on your repository and looks for a "build" or "build azure" task in your package.json file. The build command is expected to output a bundle of you site files to a build folder that you'll identify while setting up the service.

Here is the command that I used for my build command:

"scripts": {
  "compile:sass": "node-sass ./sass/main.scss ./css/style.css -w",
  "build": "copyfiles index.html web.config *.png favicon.ico manifest.json css/* img/* dist"
},

copyfiles is an npm package for copying files. You can see that the task moves all the necessary site files to the dist folder. The name of this folder can be whatever you want, you'll be supplying it to the Azure Static Website service during setup (it can be changed later too).

Once you have your site files and you've tested that your build task builds and moves your site files correctly, it's time to create the Azure static web app.  GitHub actions can be accessed from the Actions tab on the repository.  The screen shot below shows a Github action with build and deploy history.

GitHub Actions Build History

Create the Service

Log into portal.azure.com and search for the "Static Web App". It is in preview as of the writing of this post.

Azure Static Web App Summary Screen

Click "create" to start the wizard. The first entry screen looks like this.

Azure Static Web App Service Build Screen 

The fields here are straightforward, pick your resource group, give the service a name and pick a region where you want it hosted. Azure will distribute the resource globally, so the region is only important if you have data sovereignty concerns. (Note too that this service may not be available in all regions).  The region list is currently limited to:

Note the SKU choice. Free is the only option. This may because the service is in preview, but I haven't been charged for it yet, so I'm not complaining.

Click the Sign in with Github button to connect to your GitHub repo.

Azure Static Web App Service Github Integration

You can see here that I've connected to a repo called pageboy.ca and instructed the master branch be used to pull the code. The GitHub action the executes the CI/CD task will be created in this repo automatically with a secret key that allows GitHub to connect to the Azure API.

CI/CD Setup

The Build tab is next.  If you are using a Static Site Generator like Hugo or Jekyll you'll need to set the app location to the location of the built site files (Jekyll uses _site and Hugo uses dist).  For my static site I decided to run the Sass build locally and check in the CSS file.  I didn't have any api code, so I left this field and the app artifact location blank.

 Azure Static Web App Build Tab

Domain Names

Azure Static Web Apps allow you to bind one domain to your site.  For a website one domain is a SEO best practice.  The tricky thing with Azure Static Website App Services is they don't seem to expose an IP address.  They expose a randomly generated subdomain under*.azurestaticapps.net.  So you'll have to bind your custom domain via CName.

My domain registrar is not able to support CName flattening (CName flattening allows you to point an A record to a CName instead of an IP address). Which means I am stuck with the www.pageboy.ca domain for my site. For some reason using Cloudflare for my domain records did not allow me to bind to the apex domain (pageboy.ca). Even though Cloudflare supports CName flattening.

Global Distribution

Azure Static Web Apps are distributed across Azure regions to provide low latency connections to local users. I ran a pingdom test against the pageboy.ca site from Brazil to check the latency and got a 2.48sec load time. Cloudflare is likely helping this result with the CDN cache, and the page is very minimal, but this is still a good result.

Pingdom Azure Static Web App Performance Result

Using the yoursoftwaredoesnotwork.com domain which is not fronted by cloudflare returned a 1.65sec load time. I also ran a WebPageTest.org test from Brazil. The speed results are comparable.

Azure Static Web App Service WebPageTest Result

You can see that WebPageTest.org is unimpressed with my response headers on another Azure static site. The standard headers are missing. I attempted to serve them by adding a web.config to the site with the following configuration:

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <clear/>
      <add name="X-Frame-Options" value="SAMEORiGiN"/>
      <add name="X-Xss-Protection" value="1" mode="block" />
      <add name="X-Content-Type-Options" value="nosniff" />
    </customHeaders>

Security Headers

Applying a web.config to a static site did not seem to help with my security headers issue. However a few days later after I had created a few more test sites I ran them through webpagetest again and somehow the security headers were working. I suspect this is a change that Microsoft has made to the service and that my web.config is unnecessary.

Here is my latest webpagetest run.

WebPageTest result for www.pageboy.ca

Front Door and Azure DNS

I created a jekyll site for my yoursoftwaredoesnotwork.com domain and took a crack setting up the apex domain using Azure Front Door. Azure Front Door allows you to select a Web App backend by name and bypasses the apex domain issue. Currently, this is not supported. My Static Web App Service was not selectable.

Azure DNS is also unable to CName flatten, so that was also a bust. This service is evolving rapidly though - so it best to check for updates periodically.

Autoscaling and Load Performance

How much traffic can my site handle and how well do Azure Static Websites autoscale for load?

To get some quick measurements I created a Hugo based static site using the Twenty-Twenty theme and the example site content.  I also added some high quality image content to get a few pages up to a ~200Kb payload for a realistic test.

I used JMeter and had it request the home page, contact page and 3 blog post pages.  The home page and a post called pcb-layouts had large image content.  My JMeter test settings are setup as follows:

50 concurrent users is a pretty high bar and I start to run into bottle-necking issues on my system, but I wanted to put some stress on the site and see how it performed.  Here is the JMeter graph from my test run.

Azure Static Web App Performance Graph

You can see from the JMeter graph that the smaller pages have response time hovering around the 2.5 second time.  The larger pages like the home page struggle under load.  We are definitely hitting upper limits here; I consider page load time over 2 seconds to be unacceptable.  Keeping page sizes small is critical.  Adding a CDN layer to the site (via Cloudflare for example) may also help with performance.

A run with 10 concurrent users (which is a lot more realistic for a well visited blog) runs much better.  Here are some of average load times I was seeing at 10 users:

Azure Functions

Azure Static Web App Services allow you to expose a web api via Azure functions. The focus of my intial tests was with static web sites, but api support is worth mentioning. I recommend the VSCode Azure plug in to help you with the scaffolding. More details on this feature in future!

Summary

Azure Static Website App Services look very promising. I already host other resources in Azure and I like working with a familiar interface. Free certificates that I don't have to manage is a huge win.  The security headers were a bit a pain point, but that seems to have been resolved by Microsoft.  Apex domain support is not viable yet, so I have to live with www subdomains.  Load performance is acceptable, I suggest running your site through a CDN like Cloudflare to reduce load on your site and to get CName flattening.

I am in progress creating a new Hugo based blog that I will host in Azure.  I am also looking at creating a NodeJS api to go with this site which will form the content of another post.  Read my post for more information on Azure PaaS, I also have a post on Azure Front Door.

Photo by John Doyle on Unsplash

Sign-up to receive the weekly post in your inbox. I don't share email addresses, unsubscribe at any time.

Email Address