Git-based CMS for Jekyll using GitHub Actions – Part 2

In the previous post, we looked at what a git-based CMS is, and we set up a Jekyll website on our local machine. I recommend that you read the previous post here before proceeding.

In this post, we are going to be creating the necessary resources on Azure and we will deploy our website. If you don’t want to use Azure, you can use any other public cloud provider such as AWS. Most cloud providers have similar offerings to host a website along with a CDN, custom domain, and HTTPS.

Let’s deploy our website to the cloud!

We are going to be using an object store for hosting and we will use a CDN to reduce page load time for our users across the world. We will configure a custom domain and HTTPS on the CDN and not on the object store.

Side note: If the images in this post are not visible clearly, click/tap on them to zoom in.

Step 1 - Prerequisites

Create a free Azure account if you don’t have one by following the instructions provided here. Next, install Azure CLI for your operating system by following the instructions provided here. Verify that the CLI has been installed correctly by running “az –version” in your terminal. If it is installed correctly it should say “Your CLI is up-to-date” as shown below

> az --version
azure-cli 2.10.1
command-modules-nspkg 2.0.3
core 2.10.1
nspkg 3.0.4
telemetry 1.0.4
Python location 'C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\python.exe\'
Extensions directory 'C:\Users\lalit\.azure\cliextensions\'
Python (Windows) 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 23 2018, 23:31:17) [MSC v.1916 32 bit (Intel)]
Legal docs and information: aka.ms/AzureCliLegal
Your CLI is up-to-date.
Please let us know how we are doing: https://aka.ms/azureclihats
and let us know if you're interested in trying out our newest features: https://aka.ms/CLIUXstudy

Login to Azure using the CLI by running “az login” in your terminal and following the onscreen instructions.

Step 2 - Create an Azure Storage Account

Open the Azure portal by visiting “portal.azure.com” in your web browser. Create a new storage account by searching for “Storage Accounts” in the search bar on the top of the screen and then clicking on the “Add” button as shown.

Creating a new storage account
Creating a new storage account

In the multi-page form that appears, select a resource group if you already have one or create a new resource group by clicking on the “Create new” button. Select “General Purpose V2” for kind; “Hot” for access tier and “Geo-redundant storage (GRS)” for replication. Give your storage account a name, pick one of the recommended locations and click on “Review + create”. The location of the storage account does not matter because we will be using a CDN which will cache our website across the globe.

Selecting options on first tab for storage account creation
Selecting options on first tab for storage account creation

Give Azure a few seconds to run some validations. When it is done, click on the “Create” button as shown.

Azure validating storage account
Azure validating storage account

Azure will now start deploying your request and you should see something like this

Azure deploying storage account
Azure deploying storage account

While the deployment is in progress, let us take a closer look at the options that we selected:

  1. Resource Group - A resource group is a container for your resources. It is recommended that you create one resource group per project or resource type.
  2. Storage Account Name - It is a globally unique name that is used to identify your storage account.
  3. Replication - Redundancy ensures that your storage account meets the Service-Level Agreement (SLA). We picked GRS which means that Azure will copy our data synchronously three times in the primary region using LRS. It then copies our data asynchronously to the secondary region which will then be replicated using LRS. This will ensure that our website will be up even if an entire Azure region or datacenter is down
  4. Access Tier - We picked the “hot” tier as our data will be frequently accessed

Once the deployment is complete, you should see something like this. Click on “Go to resource” to go to your storage account.

Azure storage account deployment complete
Azure storage account deployment complete

Enable the static website feature by clicking on the “Static website” link in the left navigation bar and then toggling the switch to “Enabled”. In the “Index document name” enter “index.html” and in the “Error document name” enter “404.html” and then hit “Save”.

Enabling static website in the storage account
Enabling static website in the storage account

Once you hit save you should see something like this.

Static website being enabled
Static website being enabled

While that is happening, let us understand what we just did. In the previous part of this series, we saw that Jekyll generates HTML and CSS for our website and it will place them in the “_site” folder. The static website feature allows us to upload these HTML, CSS, JS, and image files to a special container called “$web” and Azure will take care of serving these files to our users. All the complex server maintenance and scaling are taken care by Azure and we don’t have to worry about it.

Once the deployment is done, you should see

Static website enabled
Static website enabled

Note down the “Primary Endpoint” someplace safe. It will come in very handy later. This is the Microsoft provided URL for our website. If you open a new tab in your browser and navigate to the endpoint now you will see an error page, i.e., a not found page. This is because we have not deployed our website to the “$web” container yet.

Step 3 - Deploy!

To deploy your website, you will need the connection string for your storage account. Get the connection string by clicking on “Access Keys” in the left navigation pane and then copy the connection string (under key 1) as shown. Note: The connection string is a password that provides complete access (root access) to all the files inside in your storage account. Do not share it with anybody.

Fetching the connection string for the storage account
Fetching the connection string for the storage account

Navigate to the directory where you stored your website. Build your website by running “JEKYLL_ENV=production bundle exec jekyll build” in your terminal. When the build completes successfully, enter the command “az storage blob sync -c ‘$web’ -s ‘_site’ –connection-string ‘«BLOB_CONNECTION_STRING»‘” in your terminal to deploy your website to your storage account.

> cd .\blog\my-awesome-site\
> JEKYLL_ENV=production bundle exec jekyll build
Configuration file: /mnt/c/Users/lalit/blog/my-awesome-site/_config.yml
            Source: /mnt/c/Users/lalit/blog/my-awesome-site
       Destination: /mnt/c/Users/lalit/blog/my-awesome-site/_site
 Incremental build: disabled. Enable with --incremental
      Generating...
                    done in 7.172 seconds.
Auto-regeneration: disabled. Use --watch to enable.
> az storage blob sync -c '$web' -s '_site' --connection-string '<<connection string>'
This command is in preview. It may be changed/removed in a future release.
Azcopy command: [...]
INFO: Any empty folders will not be processed, because source and/or destination doesn't have full folder support
Job 7dbd6075-cb6a-8c40-5d69-811004e79f3d has started
Log file is located at: C:\Users\lalit\.azcopy\7dbd6075-cb6a-8c40-5d69-811004e79f3d.log
INFO: azcopy.exe: A newer version 10.6.0 is available to download
0.0 %, 0 Done, 0 Failed, 8 Pending, 8 Total, 2-sec Throughput (Mb/s): 0
Job 7dbd6075-cb6a-8c40-5d69-811004e79f3d Summary
Files Scanned at Source: 8
Files Scanned at Destination: 0
Elapsed Time (Minutes): 0.0668
Number of Copy Transfers for Files: 8
Number of Copy Transfers for Folder Properties: 0
Total Number Of Copy Transfers: 8
Number of Copy Transfers Completed: 8
Number of Copy Transfers Failed: 0
Number of Deletions at Destination: 0
Total Number of Bytes Transferred: 69702
Total Number of Bytes Enumerated: 69702
Final Job Status: Completed

The “az storage blob sync …” will “sync” all the files that are present in the “_site” folder to the “$web” container. As we saw in part 1 of this series, the “_site” folder contains the HTML and CSS files Jekyll generated for your site. We perform a sync operation and not a batch because if there are files in the “$web” container that are not in the “_site” folder, they must be deleted. The sync command will do that, but the batch upload command will not. This will ensure that if you remove an image or post on your website it will be removed from your storage account as well.

Now open a new tab in your browser and navigate to the “Primary endpoint” that you saved in the previous step and you should be able to see your website.

Website hosted and live from the storage account
Website hosted and live from the storage account

Step 4 - CDN!

Let us add a content delivery network (CDN). A CDN will cache our website across the world in its points of presence (POPs). This will ensure quick transfer of our HTML, CSS, JS, and images to our users’ devices.

To add a CDN, click on the “Azure CDN” in the left navigation and in the form that appears, enter a “CDN profile name” in the first text box. Select “Standard Microsoft” for the pricing tier and provide a memorable URL for the “CDN endpoint name”. Ensure that in the “Origin hostname” the static website option is selected and then hit “Create”

Add a CDN for the website
Add a CDN for the website

You should now see something like this

CDN being deployed
CDN being deployed

Give it a couple of minutes to complete the configuration. When it is complete, you should see something like this

CDN deployed successfully
CDN deployed successfully

Now navigate to CDN endpoint name followed by “.azureedge.net” in a new tab. In my case the CDN endpoint name was “lalitblog”, hence I will navigate to lalitblog.azureedge.net”. You should see something like this

CDN not working? Something wrong?
CDN not working? Something wrong?

Did we mess something up? No. It can take up to 30 minutes to update the CDN POPs around the world. Please be patient and try again after some time. When I refreshed the page after 20 minutes, I was able to see my website.

Website being served using CDN
Website being served using CDN

We now have a CDN for our website. Notice that the website loads significantly faster. This is because the website is being fetched from the location that closest to you and not from the origin. In my case, my website was being fetched from the Indian CDN POP and not from US East where my website is hosted.

Step 5 - Custom domain and HTTPS!

Let us now add a custom domain to our website. I am going to be adding “blog.lalitadithya.com” as my custom domain. To add a custom domain we need to add a CNAME pointing to the CDN endpoint.

Login to your DNS provider and add a CNAME for the custom domain of your choice pointing to your CDN endpoint. In my case, I logged in to Azure DNS and then added a CNAME for “blog.lalitadithya.com” pointing to “lalitblog.azureedge.net”. DNS propagation might take some time, so wait at least about 5 to 10 minutes before proceeding further.

Switch back to your Azure portal and then click on your hostname under the endpoints subsection as shown.

Navigating to the CDN endpoint
Navigating to the CDN endpoint

Click on the “+ Custom domain” button in the top navigation bar.

Adding a custom domain - step 1
Adding a custom domain - step 1

In the fly-out menu, enter your custom domain name and click on the “Add” button. In my case, I will enter “blog.lalitadithya.com”

Adding a custom domain - step 2
Adding a custom domain - step 2

You should see:

Custom domain being configured
Custom domain being configured

Give it a few minutes to complete. Once it is complete, you should see something like this. To enable HTTPS, click on your custom domain as shown.

Custom domain configured successfully
Custom domain configured successfully

Flip the toggle switch to “On” and then click “Save”.

Enabling HTTPS
Enabling HTTPS

You should now see something like this

HTTPS being enabled
HTTPS being enabled

After about a minute, the deployment would have completed, and you should see something like this

HTTPS propagation started
HTTPS propagation started

The HTTPS propagation process can take at least half-hour to at most 2 hours, so please be patient. The page will update itself automatically when a step is complete. Once all the steps are complete, you should see something like this.

HTTPS propagation completed
HTTPS propagation completed

Now open one more tab and navigate to the custom domain. In my case, I will navigate to “blog.lalitadithya.com”. You should now see your website with your custom domain with HTTPS enabled.

Website deployed with HTTPS and a custom domain
Website deployed with HTTPS and a custom domain

Conclusion

In this post, we created all the necessary resources on Azure and deployed our website manually. We configured a CDN, added a custom domain, and enabled HTTPS. In the next post we will look at how we can build a continuous deployment pipeline using GitHub actions.

Share: Twitter Facebook
Lalit Adithya's Picture

About Lalit Adithya

Lalit is a coder, blogger, architect, and a photographer. He has been coding since 2010 and he has taken business critical websites and desktop apps from inception to production by working in/leading cross functional teams with an Agile focus. He currently focuses on developing & securing cloud native applications.

Bangalore, India https://lalitadithya.com