Statiq.Web

Static website generation

Published on Monday, February 15, 2021

The Goal

A low effort way to publish new content and keep maintenance to a minimum.

I wanted to:

  1. Edit markdown files
  2. Push files to git
  3. Website is updated

I did not want to:

  • Host a database for posts
  • Manage an admin login
  • Manage comments
  • Manage security updates

Statiq.Web

I found a neat static site generator called Statiq.Web (formerly Wyam). It converts markdown and razor markup to static HTML.


Create your first post

First, follow the setup instructions.

Then, create a new markdown file at /input/posts/my-post.md

Title: My Post
Lead: It's a good post
Published: 2021-02-15
Tags: ASP.NET
Image: posts\2021-02-15-bg.png
---
<your markdown here>

Make sure your local Statiq.Web site is running

dotnet run -- preview

You can view your site at http://localhost:5080 and as you make changes, the site will reload.


Deploy to Azure

You can use Statiq.Web's built-in Azure deployment

Add the DeployToAzureAppService() method to your Program.cs.

static async Task Main(string[] args)
{
    await Bootstrapper
        .Factory
        .CreateWeb(args)
        .DeployToAzureAppService(
            Config.FromSetting<string>("AzureAppServiceSiteName"),
            Config.FromSetting<string>("AzureAppServiceUsername"),
            Config.FromSetting<string>("AzureAppServicePassword")
        )
        .RunAsync();
}

Add an appsettings.json to your project with the following:

{
    "AzureAppServiceSiteName": "<your site name>",
    "AzureAppServiceUsername": "<username>",
    "AzureAppServicePassword": "<password>"
}

You can get your Azure App Service publish username and password by opening your App Service in http://portal.azure.com and clicking the "Get publish profile" link.

Get publish profile

Open the <yoursitename>.PublishSettings file. There are a few different profiles but the important one looks like

<publishProfile 
    profileName="<yoursitename> - Zip Deploy" 
    publishMethod="ZipDeploy" 
    userName="$<yoursitename>" 
    userPWD="<a long random string>" />

Replace the settings in appsettings.json with the values from the .PublishSettings file. Note your username will include the $.

Your appsettings.json should now look something like this:

{
    "AzureAppServiceSiteName": "mysite",
    "AzureAppServiceUsername": "$mysite",
    "AzureAppServicePassword": "rinfj9f9sv29l1add4ahkz0kb4m9dlv9evi9amjtybbwicfx71oe"
}

Now deploy your application using the built-in Statiq deploy command:

dotnet run -- deploy

Navigate to your new site.

You may notice there's a problem if you try to navigate to any of the links.

not found

We need to tell IIS how to serve our static content.


IIS Static Site Hosting

If you choose to host your site in Azure App Service, you'll need to supply a web.config to tell IIS how to serve your static content.

Add a web.config to the /input directory of your project.

I adapted my web.config slightly from this example. The author explains each section of the web.config and why it exists.

I encountered a problem where navigating to /posts or /tags was not resolving to posts.html and tags.html respectively. I had to add the following explicit routes in order to get /posts and /tags working.

<rewrite>
    <rules>
    <rule name="PostsRewrite" stopProcessing="true">
        <match url="^posts$" />
        <action type="Rewrite" url="/posts.html" />
    </rule>
    <rule name="TagsRewrite" stopProcessing="true">
        <match url="^tags$" />
        <action type="Rewrite" url="/tags.html" />
    </rule>
    <rule name="RewriteHtml">
        <match url="^(.*)$" />
        <conditions logicalGrouping="MatchAll">
        <add input="{REMOTE_PORT}" pattern=".*" />
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="{R:1}.html" />
    </rule>
    </rules>
</rewrite>

Deploy your site again.

dotnet run -- deploy

If you encounter any problems, you can use Kudu to inspect (and even edit) the web.config right in Azure. It might be quicker than editing the web.config locally and re-deploying.


Setup YAML Pipeline

The last step is to setup an Azure pipeline so that the website is automatically updated after pushing markdown to git.

Note: You can skip this step if you are comfortable manually deploying your site using dotnet run -- deploy

The pipeline does the following:

  1. Runs the pipeline whenever a commit is pushed to master
  2. Restores NuGet packages
  3. Builds the app
  4. Deploys your site using Statiq's built-in Azure App Service deploy: dotnet run -- deploy
  5. Publishes site output to an artifact attached to the build. This step isn't necessary but it could be helpful if you ever need to troubleshoot.
trigger:
- master

stages:
- stage: Build

  variables:
    - name: BuildConfiguration
      value: 'Release'
    - name: Parameters.RestoreBuildProjects
      value: '**/*.csproj'

  jobs:
    - job: 'Build'
      pool:
        name: Azure Pipelines
        vmImage: windows-2019
        demands: 
        - msbuild

      steps:
        - task: DotNetCoreCLI@2
          displayName: Restore
          inputs:
            command: restore
            projects: '$(Parameters.RestoreBuildProjects)'
            includeNuGetOrg: true

        - task: DotNetCoreCLI@2
          displayName: Build
          inputs:
            projects: '$(Parameters.RestoreBuildProjects)'
            arguments: '--configuration $(BuildConfiguration)'

        - task: DotNetCoreCLI@2
          displayName: Run Statiq
          inputs:
            command: run
            projects: 'MySite.csproj'
            arguments: '--configuration Release --verbosity normal -- deploy'

        - task: PublishBuildArtifacts@1
          displayName: 'Publish /output'
          inputs:
            pathToPublish: 'output'
            ArtifactName: '$(Build.BuildNumber)'

Conclusion

With this setup your workflow is simple:

  1. Write posts using markdown
  2. Push changes to git
  3. View the changes on your site