This post belongs to a series of posts related to the Zola static site engine.
- Zola Kickoff
- Zola Multilingual Site
- Zola Tuning
- Zola Deploy
We have reached the final step of our brief overview of how to build a simple static site with Zola. The next steps aren't strictly necessary if you only want to build the site, but they are essential if you plan to publish it online. There are many options for publishing a site, but since we're working with a static site, here's a list of services that specialize in this:
Since I'm already using GitHub to store the site's repository, I've chosen GitHub Pages as the simplest option. This guide will walk you through hosting our static site on GitHub Pages using its CI/CD features, but feel free to choose any host that best fits your needs. We'll cover just the basics, but if you want to explore further, you can check out the GitHub Pages and GitHub Actions documentation.
Create and Set Up the Repository
If you haven't done so already, let's start by creating the repository on GitHub. You need to be logged in, then click the New repository link from the dropdown menu at the top of the page.
Once you're on the new repository form, fill in the required fields (only the name is mandatory) and click the Create repository button.
You'll be redirected to the repository page, where you'll find instructions for uploading your local repository to GitHub. Next, click the Settings link, located at the far right of the repository's header menu.
On the repository's settings page, go to the Pages section. Here, change the source from which GitHub Pages will take the content and publish it. Instead of the default "Deploy from a branch", select "GitHub Actions".
GitHub Actions Workflow
Now that we've set up the repository, enabled GitHub Pages, and configured it to deploy content via GitHub Actions, it's time to create a workflow to build and deploy the site. We'll use Hugo's example workflow and modify it to suit our needs.
Let's start by creating the directory where the workflow will reside.
mkdir -p .github/workflows
Now, create the workflow file that contains all the steps to build the site with Zola and deploy it to GitHub Pages. In this example, the file is named zola-demo.yml
, but feel free to use any other name, as long as it ends with the .yml
or .yaml
extension.
cat << HEREDOC > .github/workflows/zola-demo.yml
# This workflow has been copied and modified from the Hugo starter workflow:
# https://github.com/actions/starter-workflows/blob/main/pages/hugo.yml
#
# For more information about this file, refer to the documentation page:
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions
name: Deploy Zola to Pages
# Controls when the workflow will run.
on: [push]
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Create a map of default settings that will apply to all jobs in the workflow
# and provide bash as the default shell.
defaults:
run:
shell: bash
# Allow only one concurrent deployment, skipping runs queued between the run
# in-progress and latest queued. However, do NOT cancel in-progress runs as we
# want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
# A workflow run is made up of one or more \`jobs\`, which run in parallel by
# default. To run jobs sequentially, you can define dependencies on other jobs
# using \`needs\` keyword.
jobs:
# ---------
# Build Job
build:
# Define the type of machine to run the job on
runs-on: ubuntu-latest
# Variables that are available to the steps of all jobs in the workflow
env:
ZOLA_VERSION: 0.19.2
# A job contains a sequence of tasks called steps. Not all steps run
# actions, but all actions run as a step.
steps:
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-system-path
- name: Install Zola CLI
run: |
mkdir -p \${{ runner.temp }}/zola \\
&& wget -O \${{ runner.temp }}/zola/zola.tar.gz "https://github.com/getzola/zola/releases/download/v\${ZOLA_VERSION}/zola-v\${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz" \\
&& tar --directory \${{ runner.temp }}/zola -xzf \${{ runner.temp }}/zola/zola.tar.gz \\
&& echo "\${{ runner.temp }}/zola" >> "\$GITHUB_PATH"
# https://github.com/marketplace/actions/checkout
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
# https://github.com/marketplace/actions/configure-github-pages
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
- name: Build with Zola
run: |
zola build \\
--base-url "\${{ steps.pages.outputs.base_url }}/" \\
--force
# https://github.com/marketplace/actions/upload-github-pages-artifact
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./public
# --------------
# Deployment Job
deploy:
# Jobs that must complete successfully before this job will run
needs: build
# Define the type of machine to run the job on
runs-on: ubuntu-latest
# Define the environment that the job references
environment:
name: github-pages
url: \${{ steps.deployment.outputs.page_url }}
# A job contains a sequence of tasks called steps. Not all steps run
# actions, but all actions run as a step.
steps:
# https://github.com/marketplace/actions/deploy-github-pages-site
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
HEREDOC
As soon as you push this file to the repository on GitHub, GitHub Actions will begin to run. To monitor its progress, click the "Actions" link located at the center of the repository's header menu, and you'll be able to see the status of the current workflow.
IMPORTANT: The workflow we've set up will be triggered on any push event. However, the default GitHub Pages settings only allow deployment from the main branch. Therefore, unless you change this setting, the workflow will run for pushes made to the main branch and will fail for pushes made to any other branch.
Tweak the Site
We've hardcoded some links to be relative to the root of the domain. For example, the URL in the link to the English section is /en/
, which means that if your domain is https://www.dummy.com
, the link will go to https://www.dummy.com/en/
.
If you plan to deploy the site using the domain as the base URL, everything will work just as it did in your local development environment. However, if you plan to deploy the site in a sub-path under your domain (for example, https://www.dummy.com/zola/
), the link will break. It will still point to the wrong URL (https://www.dummy.com/en/
) instead of the correct one (https://www.dummy.com/zola/en/
).
Since I'm building the site from this tutorial series in a GitHub repository, and I'll be deploying it to a user domain sub-path (http(s)://<username>.github.io/<repository>
), I need to fix the broken links to make sure they work in the sub-path context.
Let's start by updating the links in the header menu.
sed templates/macros/navigation.html -i -e 's/i\.1/get_url(path=i.1)/'
Continue by updating the links to the language sections on the homepage.
ed content/_index.md << HEREDOC
9,10s#/\([a-z]\+\)/#@/_index.\1.md#g
wq
HEREDOC
Next, update the links to the site's icons (favicons). Just like with the language links, these should be adjusted to work correctly when the site is deployed under a sub-path.
sed templates/base.html -i -e 's#href="/\([0-9a-zA-Z./-]\+\)"#href="{{ get_url(path="/\1", trailing_slash=false) | safe }}"#g'
Now, let's update the icon sources to make them relative to the manifest file. The manifest file helps configure how icons are displayed when users add your site to their home screen on mobile devices or in other contexts.
sed static/icons/site.webmanifest -i -e 's#/icons/##g'
Next, update the taxonomy links in the content footer. These links typically point to specific categories or tags in the site.
ed templates/page.html << HEREDOC
42d
41a
{% set path = [path_lang, "tags", tag | slugify] | join(sep="/") -%}
<a href="{{ get_url(path=path) | safe }}">#{{ tag }}</a>
.
47d
46a
{% set path = [path_lang, "categories", category | slugify] | join(sep="/") -%}
<a href="{{ get_url(path=path) | safe }}">+{{ category }}</a>
.
53d
52a
{% set path = [path_lang, "contexts", context | slugify] | join(sep="/") -%}
<a href="{{ get_url(path=path) | safe }}">@{{ context }}</a>
.
wq
HEREDOC
The last update is for the search page. To ensure that the search functionality works correctly when the site is deployed in a sub-path, we're going to define a BASE_URL
constant that will be used in the search UI logic. This will enable the search page to dynamically adjust its base URL based on the deployment context.
ed templates/search.html << HEREDOC
6d
5a
<script>
const BASE_URL = '{{ get_url(path='/', trailing_slash=false) }}';
const LANGUAGE = '{{ lang }}';
</script>
.
wq
HEREDOC
Finally, update the search UI logic to load the search index file using the BASE_URL
constant.
ed static/search.js << HEREDOC
47s#\`/#\`\${BASE_URL}/#g
wq
HEREDOC
Zola Container
By now, the site should be working whether the base URL is the domain or a sub-path. However, the workflow will still be triggered by any branch push. Let's update it so that the workflow only runs on pushes to the main branch of the repository. Additionally, we will use the same app that we're using locally to build the static site. Instead of manually installing Zola, we'll reuse the same container image that we use in our development environment.
Here are the updates we need to make to the workflow file.
ed .github/workflows/zola-demo.yml << HEREDOC
7a
# GitHub displays the workflow run name in the list of workflow runs on your
# repository's "Actions" tab.
run-name: "> \${{ github.event_name }} '\${{ github.ref_name }}' \${{ github.ref_type }} by @\${{ github.triggering_actor }}"
.
14d
13a
# Triggers the workflow on push event but only for the "main" branch
on:
push:
branches: [ "main" ]
.
49,52d
53,60d
64,69d
63a
# https://github.com/marketplace/actions/docker-run-action
- name: Build with Zola
uses: addnab/docker-run-action@v3
with:
image: tandiljuan/zola:0.19.2
options: --volume \${{ github.workspace }}:/app
run: |
zola build \\
--base-url "\${{ steps.pages.outputs.base_url }}/" \\
--force
.
wq
HEREDOC
Wrapping Up
With this post, we conclude our overview of Zola. We've covered how to create a site, make it multilingual, adjust it, and finally, deploy it. While I've met my goal and we've reached a point where we can use what we've learned to start publishing online, there are many other aspects that weren't covered in this series of posts.
Now, it's up to you! You already have the foundation to start building your site. If you're looking for some extra motivation... Can you publish 100 posts on your blog in a year? 😉
Take care and until next time!