HOSTING A STATIC WEBSITE ON AZURE STORAGE WITH AZURE CDN
Tags: azure, staticwebapps, tutorial, cloud
Published: 2022-11-16 03:16:46

**INTRODUCTION**
A colleague reached out to me some time ago and wanted to host a static website on Azure storage. We haven’t had time to go through the steps and achieve his goal which is to host a static website on Azure.
Now I made this demo for those who would like to host a static website on Azure cloud, specifically into an Azure Storage Account using the Azure portal. I would make this demo a step by step walk through so even you that are new to the cloud can easily host your static website on Azure Storage.


**WHAT ARE THE BENEFITS OF HOSTING YOUR STATIC WEBSITE ON AZURE?**
Okay so why should you host your static website on Azure? there are good reasons for wanting to do this as I have highlighted below;
•	Simplicity: All you have to do is upload your web folders and files to a container.
•	Saving on hosting cost: Cheaper compared to buying hosting fee from a web hosting company.
•	Better Performance: Azure CDN can be configured to get a better performance delivering contents to your end users around the world.
Combining Azure CDN with blob storage provides a low-cost and highly reliable static website hosting solution. These static sites have only CSS, HTML, JS files, fonts, etc.


**PREREQUISITES**
There are some prerequisites we have to put in place before we proceed with this demo:
•	Create a Microsoft Azure account, if you currently don’t have you can create one [here](https://azure.microsoft.com/en-us/) 
•	Create a subscription
•	Have a registered domain

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ht7cs1l0i4am7ijccle.png)

**NOTE:** To those that are new to the Azure platform, when you create a free account, you get a $200 free Azure credit to create resources for 30 days and a subscription is automatically created.


**OUTLINE OF WORKFLOW**
Below is the workflow of what we would be doing in this demo,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ton0mowa1hv5iu09u3im.png)

Our static website would have a custom domain with which our end users would be able to access our website from the public web.

After all prerequisites has been put in place, let’s get started.

**• CREATE A RESOURCE GROUP**
A resource group is a container where all related resources reside in. Now let’s proceed and create a resource group. See below images for visual guide.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hl2nx48z5hj0211rlj1.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pfujfl2x7wnzrtwm673o.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2aq7vnuo4or56ekvrho.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/06yo09119zlchxywm93x.png)

**• CREATING A STORAGE ACCOUNT**
After creating the resource group static-website-demo-rg for this demo, the next step is to create a storage account inside the static-website-demo-rg RG. See images below,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/81qxnw98n4lhizqx7ccz.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ww30uyoh6uffscxxyx1v.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/djioql111uooe1pk1s5c.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3y5xmtyfnbsahokwj5e.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytmqa6om7md64mzjnpo9.png)

Goto the newly created storage account resource which is staticwebsitehosting1 for this demo. This is where most of the task would take place. As shown in image below, this is the interface you should see when you goto the storage account.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ie66rs9cm8cg9lqe0qkr.png)

Click on capabilities and you see that the storage account at the moment is not configured for static website hosting and Azure CDN is also not configured as shown in the image above.


**ENABLING STATIC WEBSITE ON STORAGE ACCOUNT**
Now click on static website and enable the storage account to host static content webpages. 
Enter the **index.html** inside the index document block, you can also specify a root file for 404 error but we are not interested in that for this demo. Save and when it is enabled a primary endpoint **https://staticwebsitehosting1.z13.web.core.windows.net** is created automatically this is just a generic URL for your end users to access your website contents.
See images below


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ps6lmgx274f8y6y7ha9x.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7j7ojup0y95rh0dvhcrd.png)

Also, after enabling static website a container **$web** is automatically created, this container would hold your web content files and folders.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/60p4p1ummkh1z62689tt.png)

If we check capabilities under the storage account overview, we see that static website has been configured.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1t93jq5he4ajx2glpxid.png)

**UPLOADING WEB CONTENTS TO CONTAINER**
Now it's time to upload our website contents to the container **$web**. You might be thinking uploading the web content to the container from the portal should be easy by just clicking the upload button and upload the web folders and files to the container. Unfortunately, you cannot upload folders to the container from the portal directly except for files.
Here is our web content below,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8gb1fpwrvbuzw3xnftv.png)

see below image you can only upload files to the container. For our web contents only _index.html_ and _README.txt_ can be uploaded which does not work for us because all folders and files has to be uploaded

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ohg31ia407mz06dmfwqs.png)

**• DOWNLOADING AZCOPY**
To upload our web contents to the container we would make use of a tool called AzCopy. AzCopy is a CLI (command-line) tool that moves data into and out of an Azure Storage. 
Next step is to download the AzCopy tool that best fits your environment here -> [https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10#download-azcopy](https://docs.microsoft.com/en-us/azure/storage/common/storage-use-azcopy-v10#download-azcopy).
Unzip the AzCopy file, for this demo I have the AzCopy unzipped folder copied to a folder "_azmove_" in my C:\ drive root. You can add the directory location of the AzCopy executable to your system environment variable path for ease of use, but for this I will navigate to the folder where we have the AzCopy executable and copy the file full path somewhere like a notepad. See Image below


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bdp4hbgofqalsseg6911.png)

**• AUTHORIZE AZCOPY TO ACCESS STORAGE ACCOUNT**
We would need to authorize AzCopy to access the storage account so we can upload the web contents to the container. We would provide authorization credentials to AzCopy by using **shared access signature (SAS) token** generated from the storage account. Click on the shared access signature on the left pane under "_security + networking_".
Explaining the key options
**Allowed service** - check _blob_ only because we want to take into consideration one of cloud best practices which is least privilege concept. This SAS token is only intended for the blob service and no access should be granted to your file, queue or table service using the generated SAS token.
**Allowed resource type** - check container as this is the only resource, we want the SAS token to access.
**Start and expiry date/time** - set the period you want this SAS token to be valid through. Put into consideration security best practices, expiry date shouldn't elapse the period SAS token is expected to be used.
Leave other options as it is and proceed to click on generate SAS and connection string.
See Images below,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jq3o38k62tptyomlcq72.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r2rnjlw49bgzevxntnri.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztbpyrqtlza4u2m4jtdn.png)

SAS token is generated as you can see in the last image above.
Copy the SAS token somewhere like a notepad, once you leave this page you cannot retrieve the token any longer. As you can see in the image below I have copied all important path, urls, token to one point.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iw0mrjfo2dueqn8hamie.png)

AzCopy script
**_.\azcopy copy "{path to the website folder on your local pc}" "{path to the container hosting the website}{SAS token}" --recursive_**
Explaining the contents of AzCopy scripts
**.\azcopy copy** - This command copies source data to a destination location, be it from your local computer to a storage account or from a storage account to your local computer.
**--recursive** - This flag is necessary because we want to make sure it copies all sub-folders inside folders and files 
{**path to the website folder on your local pc**} - This is the source destination of your web contents, to be uploaded to the container. See image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5pf4vsq1sxhqarck7p3.png)

**{path to the container hosting the website}** - This is the target destination which is your container. To get the URL/path to your container see the images below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ymabp14wvjaapexo4jvi.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xuvmqtsiaj2u3ozk86ml.png)

Now if you remember we are making use of AzCopy because we cannot upload folders to the container using Azure portal, if we copy the source folder to the container, our web content would be nested inside another folder and this would not work. We need all folder and files of the web content to sit at the root of the
container. I have created an AzCopy scripts for each folder and file to be run and pushed to the container. see image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94llrgpume6do9o0d2jm.png)

**• RUNNING THE AZCOPY SCRIPT**
On your local pc launch cmd or PowerShell to run the AzCopy script. For this demo I am making use of cmd.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hzyan9z95vdgh17709kv.png)

Change the current working directory to where you have the AzCopy executable file by running **"cd {file path to where the azcopy exec file is}"** as shown below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jabmiod9x61mlx6i5kn3.png)

Copy the AzCopy script we coined together on notepad and past the script in cmd and run one after the other. 
**Note:** Do this for all the remaining scripts.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l1no86t3sd2ah5k1zhf8.png)

After successfully uploading the web contents, and you refresh your container you would get your web contents inside the $web container.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a9mxvq575vbgndorywex.png)

Remember the primary endpoint link [https://staticwebsitehosting1.z13.web.core.windows.net/](https://staticwebsitehosting1.z13.web.core.windows.net/) that was generated when you enabled static website on your storage account? now that is the link for your end users to access your content on the public web. See image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yfbsegwkr3lg1cpr1a0u.png)

**CONFIGURING AZURE CDN**
Now it's time to configure Azure CDN, firstly let's try to understand what Azure CDN is and its benefits to our end users.
Azure Content Delivery Network (CDN) is designed to send web contents such as audio, video, images, and other files faster and more reliably to your end users using servers that are closest to the end users. This helps to increase speed and availability, resulting in significant user experience improvements.
Below image shows Azure CDN is not configured yet.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a38kd89kiin5ng566b7j.png)

Click on Azure CDN on the left pane under the _“security + networking”_ and create a new endpoint.
Give it a CDN profile name, select the pricing tier _"select Microsoft CDN (classic)"_ give the CDN endpoint a name. 
Origin hostname - you have to select the origin server from which CDN endpoint pulls content from. I would be using my primary endpoint which is **"staticwebsitehosting1.z13.web.core.windows.net"** now proceed to create the CDN. See image below,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9v6vvew91dpo5nrtcmot.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nuhzb0cygutm4i7vhz3c.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e3elon4rxh5xdnw03mi6.png)

The last image above shows our CDN endpoint is ready and running.
Click on the newly created CDN endpoint, you can see 2 URLs one is the CDN endpoint and the other is the origin hostname aka primary endpoint for our static website. See image below,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qpfjcbkx264gjk8vcpmc.png)

Now that Azure CDN has been successfully configured for our setup, we can proceed to load the URL of the CDN endpoint which is [https://swcdn.azureedge.net](https://swcdn.azureedge.net)
**Note:** It would take some time for Azure CDN to load your content you might get the blue screen error or _"the account being accessed does not support http"_ error. Just give it sometime and refresh after some minutes. See Images below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eow2jntxwnlwrbx23v9l.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgamfgekh6ru6wyh2q4a.png)

**CONFIGURING A CUSTOM DOMAIN TO YOUR AZURE CDN ENDPOINT**
Now can you imagine your end users accessing your webpage using the URL [https://swcdn.azureedge.net](https://swcdn.azureedge.net) of course you wouldn’t want that, you would want them to access your webpage using your preferred domain name which can be an existing one for your business or a newly registered domain name.
For this demo I would be using an existing domain I registered on Azure _"theproliproject.com"_ and another registered on Namecheap _“mast***.org”_. I will be making 2 demonstrations for domain registered on Azure portal and domain registered by a different registrar.
**• Domain registered on Azure portal.**
Goto App Service Domain and select the domain. See image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24o4my6s9hhct1yhr80o.png)

What we want to do? we want to create a CNAME record with the DNS provider for _"theproliproject.com"_ that points to _"swcdn.azureedge.net"_ doing this we would be able to associate the domain to the CDN endpoint. After selecting the domain, click on manage _DNS_ records and click on _record_ set.

For this demo I am making use of a sub domain **staticweb.theproliproject.com**
• Enter the name i.e. the subdomain name
• Enter the type - you are creating a CNAME record, this is because you are mapping/pointing your host name to another name record which is _"swcdn.azureedge.net"_
• Leave Alias record set to No
• TTL - leave at default
• Alias - is the CDN endpoint _"swcdn.azureedge.net"_
Click ok after entering the appropriate information’s. See images below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ysokhkxww1jzu3nnbyfx.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9y2xwq9bv2e1b2bm229y.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16rcdaee1a4escvw4wrh.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/atu4331w5l8vvpzkzexq.png)

After successfully creating the DNS record, we can proceed to Azure CDN and map our custom domain to Azure CDN. Goto the Azure CDN and click on custom domain
Enter custom hostname - enter your subdomain here for this demo **"staticweb.theproliproject.com"** click add

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xrz97nfl0pb2ogtxq5wi.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drdpokom492ccq2891lg.png)

If you load the **staticweb.theproliproject.com** in your web browser you would get the **warning: potential security risk ahead** warning message. If you proceed to accept the risk and continue the website loads but with the SSL certificate missing as shown in image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ws0w3n31b4pb65xhca7b.png)

Now let us proceed to enable https which enables you to deliver your web contents to your end users securely over the public web.
To enable https, click on the custom domain just created and toggle the enable https feature. 
See image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uozzly6djzt7tz4s3eu8.png)

After enabling https, Azure then undergoes the following processes;
- Submits your https request
- Validates your domain.
- Provision a certificate for your domain.
See image below,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zleu4vnbe9x6gv6ewrvz.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a39luzxh1d3co8lsmrga.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/996midcc1c2h98sch2r5.png)

After the process is completed, you can reload the URL in your browser and your website should be secured with a SSL certificate.
**Note:** it might take up to 5 minutes for this process to get completed.
See image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otqlq5wob0rwqtcnucpl.png)

**• Domain registered with another registrar**
Login to your account dashboard of your registrar/host account and navigate to where you can manage your domain. 
Enter a CNAME record with the host name which is your preferred subdomain name e.g., for this demo _"staticweb"_ and the value which is the Azure CDN endpoint _"swcdn.azureedge.net"_. See image below,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3a3o0u0xf3nhasi7nqg.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mv68i9g3krg8vdttbxug.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/se225tmmpa7j7jmqlgij.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s1fq805vtjvou4aw920v.png)

Once the CNAME record is successfully added, proceed to Azure portal and add the custom domain under the Azure CDN configuration as shown in the image below,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/luibppso61ii8n713jmu.png)

If you proceed to load the website without enabling https you would get security warning error as shown in the image below

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yocev099lf3i6fi13ecp.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcmhy4mmnmsc1gs6ufy2.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6za8szu2xpswbddsrt6.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aenwv1euzk0x2jxmgrn6.png)

Now proceed to enable https

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qtuqe887is2e8o5nmeuf.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4sddtx9w04p65p0h26sp.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihidnkflzk8uen57ekts.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/247pkmb4ia1exl40g96u.png)

Now your website is secured proceed to reload the URL.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klzxvhp8fopmji040k12.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80aladmksernt5ms5iyj.png)

**RESOURCES**
[https://github.com/balop3e/static-website-demo](https://github.com/balop3e/static-website-demo)
[https://aka.ms/downloadazcopy-v10-windows](https://aka.ms/downloadazcopy-v10-windows)
[https://mega.nz/file/YKdBXYIQ#nBlYomzljIKF9QXLmdvQwhA45iKLOw-lNXyuaJ6uPVU](https://mega.nz/file/YKdBXYIQ#nBlYomzljIKF9QXLmdvQwhA45iKLOw-lNXyuaJ6uPVU)

**CONCLUSION**
In this demo we just saw how to host a static website on Azure using the Azure portal. In future posts, I will be hosting this static website using Azure DevOps Pipelines, Git, GitHub and Terraform.