I initially migrated the blog over from Wordpress over to Jekyll and a Static Web App in Azure. I was very happy with how quick it was to do and how easy it is to setup. You even get a free SSL certificate included with the Static Web App. However you cannot use naked domains (without the www or anything), and while I can easily point everything to include this, I generally find it cleaner on URLs without it.
Migrating to a regular App Service won’t actually solve this problem either, as you can still get a free SSL certificate using the App Service Managed Certificate functionality, however this also does not support naked domains. What is supported though is Let’s Encrypt.
In fact, if you are running a Windows stack on your App Service, you can install an extension which automates the whole process after the initial installation. This is very helpful and takes the management out of the Let’s Encrypt certificates. You can also issue them on the command line using Certbot as well and OpenSSL. This is very handy if you are running a Linux App Service Plan where extensions are not supported.
Building the GitHub Actions file
Without further delay, let’s look at how you can build the GitHub Actions file to take your code from your repository and deploy the Jekyll powered site into your Azure App Service. We will follow the following steps to achieve this:
- Execute on either a push to master or pull requests to master
- Checkout code from repository
- Install Ruby
- Install Bundle dependencies
- Execute a Jekyll build
- Deploy to our Azure App Service
It’s quite a simple process and we can achieve this in less than 50 lines of YAML.
First of all we need to define how the workflow will be executed, this is defined in the on
section as shown below. We declare that this workflow will run when pushes occur against the master branch or a pull requests which is opened, synchronized, reopened or closed is executed on the master branch. This allows you to work in development branches without the workflow executing on every commit.
on: push: branches: - master pull_request: types: [opened, synchronize, reopened, closed] branches: - master
Next we define the jobs which are executed in the workflow, this is done using the jobs:
keyword. First, as a security blanket, we can add in an if
statement, which controls when the jobs run. This statement just matches the conditions we have specified above.
jobs: build-and-deploy: if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
Next we move into the steps which start to build the code. First of all we need to define what type of agent the workflow will be executed on. This is done using the runs-on:
keyword. For this example, we are using ubuntu-latest
, we also give the job a name, which is Build and Deploy Job.
Now we define the steps to checkout the code from the repository, you can do this with the code shown below after the steps:
keyword.
- uses: actions/[email protected] with: submodules: true
Now we have a working copy of our source code from Git, we can now install Ruby, this is the programming language used by Jekyll. We can also specify the specific version if required.
- name: Install Ruby uses: ruby/[email protected] with: ruby-version: 2.6
Next to install all the dependencies found in the Gemfile definition within the Jekyll installation, we execute a basic command, this is built in, so we don’t need the uses:
keyword for this step.
- name: Install Dependencies run: bundle install
We can also execute the build command on the Jekyll CLI the same way, as the dependencies file defines the installation of Jekyll which includes the CLI tools. The following will build the site.
- name: Jekyll Build run: jekyll build
Next is the command to push the deployment to our Azure App Service. This can be done a number of ways, in this example I am using the Deployment Profile from the portal. First you will need to define a new secret in the repository settings, call it whatever you like and paste in the contents of the profile and save the secret.
- name: 'Deploy to Azure Web App' uses: azure/[email protected] with: app-name: 'myappservice' slot-name: 'production' publish-profile: $ package: "/home/runner/work/myrepo/myrepo/_site"
Notice a few things with the command above. First of all, in the app-name:
keyword, you need to define the name of the App Service in your Azure subscription. If you are using deployment slots in your App Service, you can also define which deployment slot will receive the deployment. Next you have to define the variable for the secret you have created previously.
Finally, in the package:
keyword, you will be able to define the path to a directory or a ZIP file you want to deploy, there is no need to create the ZIP file first, simply enter the working path to the /_site
directory which is the output of the build command for Jekyll. If your path is different to the one above, then you can look at the output of the jekyll build
command in the workflow and see what the path is.
Source Code
Here is the source code, you can load this YAML into your GitHub Actions page as a new workflow.
name: Build and Deploy Jekyll Siteon: push: branches: - master pull_request: types: [opened, synchronize, reopened, closed] branches: - masterjobs: build-and-deploy: if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') runs-on: ubuntu-latest name: Build and Deploy Job steps: - uses: actions/[email protected] with: submodules: true - name: Install Ruby uses: ruby/[email protected] with: ruby-version: 2.6 - name: Install Dependencies run: bundle install - name: Jekyll Build run: jekyll build - name: 'Deploy to Azure Web App' uses: azure/[email protected] with: app-name: 'm12d' slot-name: 'production' publish-profile: $ package: "/home/runner/work/m12d/m12d/_site"
Summary
There you have it, if you still want to make use of the features in an Azure App Service but want to deploy your static web content for example using Jekyll, then this is all there is to it. It’s simple to do and you can still take advantage of all the great features with an Azure App Service.