Static Website hosting in Azure Storage with Custom Domain and SSL support using Azure Application Gateway
Recently I worked on architecture of cloud project which has a requirement to host static website content. Microsoft released static website hosting support in Azure Storage accounts in preview mode. This is pretty useful feature, but it has some limitations: for the time being you cannot configure it with custom domain and SSL support. As a workaround Microsoft recommends using Azure CDN to access storage account containers with custom domain over HTTPS. If you have a requirement to use CDN functionality in your cloud solution this is a pretty complex, but correct approach for deployment: you need to configure CDN provider and endpoints; not all providers are supported (like Akamai); HTTP to HTTPS redirection requires Premium offering etc.
I managed to solve it with relatively simple way using Azure Application Gateway. Azure Application Gateway is L7 load balancer performing SSL offloading, supporting custom domain (using CNAME alias), HTTP to HTTPS redirection and forwarding requests directly to Azure Storage account endpoint. Below you can find architecture diagram of solution:
To simplify sample deployment and testing, I’ve created and pushed simple Terraform project with solution on GitHub repository. I am not going to make a deep dive to Terraform support in Azure, you can google it and find a lot of articles and examples. I will focus on what you need to configure in variables. After repository cloning, you need to edit vars.example (feel free to rename it to vars.tfvars) file and change some parameters before you apply this configuration to Azure:
# Add you Azure Subscription IDsubscription_id = ""# Add your App ID you are using for Azure Terraform providerclient_id = ""# Add your Service Principal secret you are using for Azure Terraform providerclient_secret = ""# Add your Azure AD Tenant IDtenant_id = ""# Leave this default or changeresource_group_name = "storage-static-test-rg"# Leave this default or changevirtual_network_address_space = ["172.16.0.0/12"]# Leave this default or changeappgw_subnet_addr_prefix = "172.16.1.0/24"# Leave this default or changedeployment_region = "eastus"# When you apply this configuration first time, leave it as is, later you will need to change itstorage_domain_name = "example.com"# Leave this default or change (make sure it is globally unique)storage_account_name = "mystorageaccount"# Change this value to your domain namecustom_domain_name = "www.myportal.com"# Change this value to path to your PFX SSL certificate filessl_cert_file = "mycert.pfx"# Change this value to your PFX SSL certificate passwordssl_cert_password = ""
Important notes: unfortunately, for the time being not all features of Azure resources are supported in Terraform. For example, Static Website feature is not supported in Terraform yet, that is we cannot code it in Terraform, get primary endpoint as an output variable and configure application gateway. So, we will create initial configuration using some dummy value like example.com and then change it to generated Azure Storage primary endpoint value and apply new domain name again. Another point, — you need to obtain valid SSL certificate, convert it to PFX format and define path to file and certificate password values in vars.example file.
So far so good. Now you need to plan and then apply your configuration with terraform plan and terraform apply commands. After deployment process is completed, go to Azure Portal, navigate to you resource group and storage account. Go to Static Website blade and enable this option. Provide index document name (e.g. index.html) and note primary endpoint value. Do not forget to save you changes.
Now it is time to edit file with Terraform variables values and change storage_domain_name variable value to the one you have obtained on previous step: (e.g. teststaticsa51298.z13.web.core.windows.net). Then apply these changes to your existing infrastructure with terraform apply command.
Note, that we’ve configured our storage account to allow access only from our Azure virtual network and subnet appgw-subnet, where Application Gateway is deployed. It means that we can perform SSL offloading with Application Gateway and securely forward requests to storage account without any encryption, since firewall rules allow requests only from application gateway subnet. You find more about Azure Storage Firewalls and Virtual Networks in documentation.
Now we need to upload some static content to $web container. You can use any tool like Azure Storage Explorer or Azure Portal to perform this.
Important note: when you enable Azure Storage Virtual Network and Firewall Rules support you cannot access to storage container content even with Azure Portal. This is pretty strange, but clearly defined in documentation. As a workaround, in our case, you can temporary disable virtual network support, upload static website content and enable it again.
Once you applied a new configuration with storage account endpoint and uploaded a content to storage account, do not forget to create a CNAME alias to point DNS address to Application Gateway. Then go to Azure Portal, navigate to resource group, application gateway and Backend Health blade to ensure that your backend pool is healthy.
It seems everything goes fine, and you can try to open your favourite browser and navigate to domain name you provided in configuration (do not forget to use https scheme in URI since we have not configured http to https redirection yet). In my example I’ve used self signed SSL certificate, but for production deployments you should use valid CA signed one.
You’ll be surprised with error message: «The request URI is invalid». The reason behind that is storage account requirement of correct host header with primary endpoint value. Good news that Application Gateway supports host header override in HTTP settings. You can find out more about Multi-tenant support feature in documentation. Bad news that for the time being you cannot code it with Terraform. To configure this option, navigate to HTTP Settings blade of application gateway resource, click on frontend-http-settings configuration we created with Terraform, go to Host name property and provide storage account primary endpoint value. Do not forget to save your changes!
When deployment process is completed try to refresh your browser.
Now it works! You can enjoy your web page, requested from Azure Storage Account with custom domain and SSL support. I’ve used as example one of the website templates from https://colorlib.com but you can use any other that you need.
Now you can configure HTTP to HTTPS redirection in Application Gateway, but I’ll leave this as a homework ;).