Post Details

Setup a Pelican site on Azure Static Web Pages with Staticman comments

Tutorials

Setup a Pelican site on Azure Static Web Pages with Staticman comments

Pelican is a great tool for creating flat HTML websites like a blog. The utility allows you to create pages using Markdown, and then converts them to HTML using a theme. The result is a website that doesn't have a lot of overhead from a backend dynamically generating content, querying a database, or having a backend exposed to the internet. Other similar tools include Jekyll, Hugo, and Eleventy.

There are some important caveats to using something like Pelican though, namely the flexibility of the backend to allow for more interactivity, such as comments on a blog post. To handle that, we can utilize something like Staticman to leverage GitHub as a means of storing these comments.

Here is the general process of how I set up a Static Web App on Azure with Pelican and Staticman. You could probably do something very similar using any static site generator and achieve the same end goal; a simple HTML website with comment functionality hosted on Azure.

Create a static web page in Azure

  1. I created a new resource group called rg-apps. Following the Azure Cloud Adoption Framework, resource groups should be created to help manage resource lifecycle, so this resource group should contain everything related to your static web app.
  2. Give the app a name. Keep it simple because Azure has constraints around the naming here, but as a general rule, it should be self-documenting.
  3. Select the tier you want to use from Free, Standard, and Dedicated. I selected Free because this is not a heavy load website by design.
  4. For deployment details, I selected Other initially and configured the workflow manually. You could also select GitHub or DevOps and let it automatically configure the workflow, but you'll need to edit it later anyways.
  5. On the Advanced page, select a region that makes sense.
  6. Add tags if necessary/desired and deploy! I'm willing to bet you don't have Azure Policy configured to require tags anyways #challenge

Configure static web page

Cool, we have our Static Web App, but it's completely empty (probably). Now what? Lets get our GitHub CI/CD pipeline setup to automagically build and deploy our site!

  1. From your new Static Web App, note the deployment token by clicking Manage Deployment Token in the top bar of the Overview blade (next to the Refresh and Delete buttons).
  2. Go to the GitHub (or whatever) repository and set up a new CI/CD workflow. I'll use GitHub because that’s what everyone typically uses, but Azure DevOps works too, and you can probably get this to work on GitLab or BitBucket as well. YMMV.
  3. Go to the Actions tab and click New Workflow
  4. Search for "Deploy web app to Azure Static Web Apps" and click Configure
  5. Customize the workflow file. You'll need to have a build phase that builds your pelican site
build:
  if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') || github.event_name == 'workflow_dispatch'
  runs-on: ubuntu-latest
  name: Build Pelican Site
  steps:
    - uses: actions/checkout@v4
      with:
        submodules: true

    - name: Set up Python 3.12
      uses: actions/setup-python@v5.2.0
      with:
        python-version: 3.12

    - name: Install pelican with markdown
      shell: bash
      run: "pip install invoke pelican[markdown]"

    - name: Install YAML
      shell: bash
      run: "pip install pyyaml"

    - name: Build the project
      shell: bash
      run: "pelican content -s publishconf.py"

    - name: Check if we have everything
      shell: bash
      run: "ls -la output/"

    - name: Store output for deployment
      uses: actions/upload-artifact@v4
      with:
        name: pelican-site
        path: "output/"
  • We can modify the workflow to allow for manual triggering of the job

    1. Add workflow_dispatch to the on: node at the top. This tells the workflow that we can manually kick this off.
    2. Add an additional or condition to the if then statements on the build and deploy phases to allow these jobs to run when github.event_name == 'workflow_dispatch'
  • You'll need to have a deploy phase that pushes the artifacts from the build phase to the Azure Static Web Page app

deploy:
 if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') || github.event_name == 'workflow_dispatch'
 runs-on: ubuntu-latest
 needs: build
 name: Deploy Job
 steps:
   - uses: actions/checkout@v4

   - name: Get built pelican site
     uses: actions/download-artifact@v4
     with:
       name: pelican-site
       path: "output/"

   - name: Deploy
     id: deploy
     uses: Azure/static-web-apps-deploy@v1
     with:
       azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
       #repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (i.e. PR comments)
       action: "upload"
       ###### Repository/Build Configurations ######
       app_location: "output/" # App source code path relative to repository root
       #api_location: "api" # Api source code path relative to repository root - optional
       output_location: "public" # Built app content directory, relative to app_location - optional
       ###### End of Repository/Build Configurations ######
  • We don't need a ton of options under the deploy step, mainly the azure_static_web_apps_api_token, action, app_location, and output_location
  • This will take the artifacts from the output directory that were built in the previous phase, and then upload them to the Azure Static Web App.

  • Go to the Settings for your repo, and find the Secrets and Variables section

  • Under Actions add a new repository secret called AZURE_STATIC_WEB_APPS_API_TOKEN and populate it with the deployment token from step 1. Save it, and remember you may need to periodically update that deployment token. You'll never be able to view it from here after creating/updating it.
  • Run the workflow to initially build and deploy the static website. This workflow will also trigger whenever a push, or merge happens on the Main branch.

The recommended procedure here is to make changes (like writing a new blog entry) in a branch, and then merge via pull request into Main when you're ready to publish the changes. The CI/CD pipeline takes care of the rest!

Add custom domain to Static Web App

Your static web app will have an automatically generated FQDN that you will be able to use to visit your site. Also, fun fact: your site will get an SSL certificate automatically as well! This automatically generated FQDN is probably not suitable for production use, so you'll want to associate a custom domain.

  1. Select Custom Domains from the menu on the left
  2. Click Add at the top and select the appropriate option
  3. There are three options: Custom domain on Azure DNS, Custom domain on other DNS, or New Custom Domain.
  4. The steps to add the domain will differ depending on which you select. The first two will have similar steps.

    1. Define the domain name
    2. Verify it using a TXT record
    3. Associate the domain with the public IP of the Static Web App
  5. The last option will guide you through the process of purchasing a new domain name.

  6. Follow the steps to finish verifying and adding your domain.

  7. Click on Add a CNAME, ALIAS, or A record once you are ready to publish your site via DNS. You'll likely need to create an A record for @ pointing to the public IP of the Static Web App.

Setup a Function App for Staticman

Now our website is there, but comments are still not working. We need to set up Staticman to handle our commenting. I'm not going to cover configuring Staticman with your website, but am assuming that you will be able to follow the Staticman documentation for that. This will only cover getting Staticman running within Azure.

  1. Go to the Staticman GitHub repo and fork the repository. This will allow you to "code lock" your staticman app, and control when to upgrade stuff.
  2. Create a new App Service.

    • I added the App Service to the same resource group as the static web page because they have a shared lifecycle (Azure CAF again).
    • Give it a name that is self-documenting.
    • for Publish select the Code option
    • Staticman is a Node.JS app, so make sure to select Node and a current version as the runtime stack.
    • Select the Linux OS.
    • Select a Region that makes sense.
    • Create a new Linux Plan giving it a name that makes sense and select the appropriate Pricing Plan.
    • On the Database page, leave everything blank and continue
    • On the Deployment page, configuring Continuous Deployment with our options isn't supported, so we'll take care of this later.
    • Accept the defaults for the Networking page.
    • If you want, you can enable Application Insights and/or Microsoft Defender for Cloud.
    • Again add tags if you want/need. You should really consider Azure Policy to take care of that for you...just saying.
  3. After the App Service has deployed, navigate to Deployment Center

  4. Select GitHub as the source

    1. Sign in and authorize GitHub if you haven't already
    2. Select your Staticman fork repo
    3. Create a new User-assigned Identity
    4. Save. This will create the necessary workflow and secrets to build and deploy the Node.JS app, and kick off an initial job to do just that. Wait for the build and deploy to complete successfully.
  5. Sign up for GitHub Developer

  6. Create a new GitHub App by going to your profile or organization settings, clicking on Developer Settings, and clicking New GitHub App.
  7. Grant the following permissions to the app for the blog repository

    • Contents - Read & Write
    • Metadata - Read-Only
    • Pull Requests - Read & Write
  8. Register the application here. Note the App ID

  9. Generate a private key for the app and open the .pem file that downloads.
  10. Back in the App Service, add Environment Variables

    1. NODE_ENV This should be production, development or test
    2. GITHUB_APP_ID This is the App ID of the GitHub App we just created
    3. GITHUB_PRIVATE_KEY This will be the ENTIRE contents of the .pem private key file, however, after pasting it in (converts to single line), we need to open Advanced edit and add \n line breaks after the opening and before the closing: -----BEGIN RSA PRIVATE KEY-----\n ... \n-----END RSA PRIVATE KEY-----.
    4. RSA_PRIVATE_KEY should be the same process as the GITHUB_PRIVATE_KEY, but generate your own RSA key for this. Use OpenSSL and use a decent key size.
    5. AKISMET_SITE This is the URL for your homepage, i.e. https://mysite.com
    6. AKISMET_API_KEY Go get a free Akismet key for your personal blog. Seriously, just go sign up and it's free.
  11. Visit your GitHub Apps installation URL, which should be something like, but not necessarily https://github.com/apps/mysite-staticman. Authorize the app to access the things.

  12. Test Staticman by visiting your App Service app at the following URI /v2/connect/<GITHUB_USERNAME>/<SITE_REPO_NAME>. You should get an OK! message.

At this point, your blog and Staticman should be up and running in Azure Static Web App and Web App Service. You may need to massage some of the config for your site accordingly to make sure that the comments form points to the right place, and all that stuff. But I think I've done enough to help you for now.

Happy blogging!