Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

My Learn Base

Live site: mylearnbase.com Repository: github.com/RustWright/mylearnbase

My Learn Base is a personal learning journal and portfolio site. It documents projects, experiments, and things I find interesting — serving both as a reference for my future self and a resource for others.

Tech Stack

LayerToolPurpose
Static site generatorZolaConverts markdown into HTML
ThemeSereneProvides the visual design
HostingCloudflare PagesServes the static site globally
DocumentationmdBookThis documentation

How It Works

The site is fully static — there’s no server-side code running. The workflow is:

  1. Write a post in markdown with TOML frontmatter
  2. Zola combines the markdown with HTML templates and generates plain HTML/CSS/JS
  3. Push to GitHub, which triggers Cloudflare Pages to rebuild and deploy

The result is a fast, secure site with zero hosting costs.

Project Goals

  1. Blog/Learning Journal — Document processes when working on projects, with series-based multi-part posts
  2. Portfolio — Showcase completed work and host interactive demos (future)
  3. Monetization — Organic revenue generation to cover maintenance costs (future)

Design Priority

Authoring experience first. If it’s frictionless to create content, content gets created consistently.

Prerequisites

Required

Zola

Zola is the static site generator that builds the site. Install version 0.22.1 or later.

Linux (recommended):

# Download and extract
curl -sL https://github.com/getzola/zola/releases/download/v0.22.1/zola-v0.22.1-x86_64-unknown-linux-gnu.tar.gz | tar xz

# Move to a directory in your PATH
sudo mv zola /usr/local/bin/

# Verify
zola --version

Other platforms: See the Zola installation guide.

Git

Required for cloning the repo and managing the Serene theme (which is a git submodule).

git --version  # Should be 2.x or later

Optional

mdBook

Only needed if you want to build this documentation locally.

# Requires Rust/Cargo
cargo install mdbook

# Verify
mdbook --version

Rust / Cargo

Only needed for installing mdBook or for future WASM demo development.

See rustup.rs for installation.

Local Development

Clone the Repository

# Clone with submodules (important — the theme is a submodule)
git clone --recurse-submodules https://github.com/RustWright/mylearnbase.git
cd mylearnbase

If you already cloned without --recurse-submodules:

git submodule update --init

Set Up Git Hooks

The repo includes a pre-commit hook at .githooks/pre-commit that automatically sets the updated frontmatter field on any modified post. The hook runs on every commit and does the following:

  1. Finds staged .md files in content/posts/ that were modified (ignores _index.md)
  2. Reads each file’s last-modified date from the filesystem
  3. Skips the file if that date matches the original date field (i.e. no update needed)
  4. Inserts an updated field after date if one doesn’t exist, or updates it if it does
  5. Re-stages the file so the new frontmatter is included in the commit

The template already handles the display — if updated exists and differs from date, it renders “Updated on [date]” next to the publish date.

To enable the hook, configure git to use the tracked .githooks/ directory:

git config core.hooksPath .githooks

This only needs to be run once per clone.

Run the Dev Server

zola serve

This starts a local server at http://127.0.0.1:1111 with live reload — any changes to content, templates, or styles automatically rebuild and refresh the browser.

Project Structure

mylearnbase/
├── zola.toml              # Site configuration
├── content/               # Markdown content (what you write)
│   ├── _index.md          # Homepage
│   └── posts/
│       ├── _index.md      # Blog section config
│       └── *.md           # Individual posts
├── templates/             # Template overrides (customizations)
├── themes/serene/         # Serene theme (git submodule — don't edit)
├── sass/                  # SCSS style overrides (currently empty)
├── static/                # Static files copied as-is to output
├── public/                # Build output (gitignored)
└── docs/                  # This documentation (mdBook)

Build for Production

zola build

Output goes to public/. This is what gets deployed to Cloudflare Pages.

Check for Errors

zola check

Validates internal links, external links, and configuration without building the full site.

Deployment

The site deploys automatically to Cloudflare Pages on every push to the main branch.

How It Works

Push to GitHub → Cloudflare detects change → Runs build command → Deploys to CDN

No manual deployment steps needed.

Cloudflare Pages Configuration

SettingValue
Production branchmain
Build commandcurl -sL https://github.com/getzola/zola/releases/download/v0.22.1/zola-v0.22.1-x86_64-unknown-linux-gnu.tar.gz | tar xz && ./zola build
Build output directorypublic
Custom domainmylearnbase.com

Why the custom build command? Cloudflare Pages no longer pre-installs Zola. The build command downloads Zola on each build, then runs zola build. This adds a few seconds but is reliable.

Domain Setup

The domain mylearnbase.com was migrated to Cloudflare’s nameservers (from Porkbun) and configured as a custom domain in the Cloudflare Pages dashboard. HTTPS is handled automatically by Cloudflare.

Known Issue: Preview URLs

Cloudflare Pages generates preview URLs for non-production branches (e.g., abc123.mylearnbase.pages.dev). These previews may have broken CSS because Zola generates URLs based on base_url in zola.toml, which is set to https://mylearnbase.com. The preview URL doesn’t match, so absolute paths to CSS files break.

Workaround: Test locally with zola serve instead of relying on preview URLs for visual verification.

Architecture Overview

The Data Flow

When you run zola build (or push to GitHub, triggering Cloudflare), this is what happens:

1. Zola reads zola.toml for configuration
2. Scans content/ for all .md files
3. Parses frontmatter (TOML between +++) and body (markdown)
4. For each page: picks the right template, injects the content
5. Auto-generates taxonomy pages (/tags/meta/, /series/building-my-website/)
6. Compiles sass/ into CSS
7. Copies static/ files as-is to the output
8. Writes everything to public/

The output is entirely static HTML, CSS, and JS — no server-side processing at request time.

The Override System

Zola has a layered file resolution system. When it needs a template or stylesheet, it checks:

  1. Your project’s files first (templates/, sass/)
  2. The theme’s files second (themes/serene/templates/, themes/serene/sass/)

If you place a file in your project with the same name and path as one in the theme, yours wins. This is how you customize behavior without editing the theme directly — and it means theme updates won’t overwrite your changes.

Template Inheritance

Every page template follows a chain:

Your template (e.g., templates/blog.html)
    └── extends → Theme's _base.html
                      └── defines blocks: {% block content %}, {% block title %}, etc.

The base template (_base.html from Serene) provides the HTML skeleton — <head>, navigation, dark mode toggle, scripts. Your templates fill in specific {% block %} sections with page-specific content.

Technology Decisions

DecisionChoiceAlternatives ConsideredDeciding Factor
FrameworkZolaDioxus 0.7, Leptos, AstroDioxus SSG was broken; Zola validated and mature
ThemeSereneTabi, AbridgeMinimal, dark mode, blog-focused
HostingCloudflare PagesGitHub Pages, Vercel, NetlifyFree, global CDN, future Workers option
Content formatMarkdown + TOMLDatabase, CMSSimplicity, editor-friendly, portable
Future interactivityWASM islandsFull SPA rewriteAdditive approach, no rewrite needed

Future: WASM Islands

When interactive demos are needed, the approach is additive:

  1. Create a separate Rust crate for each demo (e.g., demos/sorting-viz/)
  2. Compile to WASM
  3. Output .wasm + .js files to static/wasm/
  4. Embed in posts via <div> + <script> tags
  5. Zola serves these as static files — no backend needed

The existing site structure, URLs, and deployment pipeline stay unchanged.

Content Structure

Sections vs Pages

Zola has a two-level content system:

  • Sections — defined by _index.md files. They set rules that apply to all pages within that directory.
  • Pages — any other .md file. These are the actual content (blog posts, standalone pages).
content/
├── _index.md              ← Section: the homepage
└── posts/
    ├── _index.md          ← Section: configures the blog listing
    └── hello-world.md     ← Page: an individual post

The _index.md in posts/ is not a post itself — it configures the entire section. Its page_template = "post.html" setting means every .md file in content/posts/ automatically uses post.html as its template without you specifying it per post.

Homepage (content/_index.md)

Uses the home.html template from Serene. Configured to show the 5 most recent posts. The markdown body after the frontmatter becomes the homepage description text.

Key settings:

  • recent = true — shows recent posts
  • recent_max = 5 — limits how many
  • links = [] — no social links yet (can add GitHub, Twitter, etc.)

Blog Section (content/posts/_index.md)

Configures how the blog listing and all posts behave:

  • sort_by = "date" — newest posts first
  • template = "blog.html" — the listing page template
  • page_template = "post.html" — template for every post in this section
  • insert_anchor_links = "right" — clickable # links appear beside headings
  • generate_feeds = true — RSS feed for this section

The [extra] section controls Serene-specific features:

  • toc = true — table of contents sidebar on posts
  • copy = true — “copy” button on code blocks
  • outdate_alert = false — staleness warning (disabled by default)

Taxonomies

Taxonomies are Zola’s grouping system. Three are configured:

TaxonomyPurposeExample
tagsTopic labels["rust", "zola", "web"]
categoriesBroad grouping(not actively used yet)
seriesMulti-part post sequences["Building My Website"]

When a post declares tags = ["rust"] in its frontmatter, Zola automatically:

  1. Creates a page at /tags/rust/ listing all posts with that tag
  2. Creates a page at /tags/ listing all tags

The same applies to series — /series/building-my-website/ is auto-generated.

File Naming

Post filenames don’t affect URLs when a slug is set in frontmatter. The file placeholder-test-post.md with slug = "hello-world" produces the URL /posts/hello-world/.

This means you can rename or reorganize files without breaking links — the slug is what determines the URL.

Templates & Overrides

The project overrides 6 template files from the Serene theme. Some are modifications of existing theme templates; others are entirely new.

Override vs Custom

TemplateTypeWhat it does
templates/blog.htmlOverrideBlog listing page — changed back link to “Home”
templates/post.htmlOverrideIndividual post — added series link display
templates/tags/list.htmlOverrideAll tags page — changed back link to “Home”
templates/tags/single.htmlOverrideSingle tag page — changed back link to “Tags”
templates/series/list.htmlCustomAll series page — no theme equivalent exists
templates/series/single.htmlCustomSingle series page — no theme equivalent exists

blog.html — Post Listing

Renders at /posts/. Lists all posts with title and date.

Key customization: The back link says ← Home instead of the theme’s generic text, so users know where they’re navigating.

The template supports two display modes controlled by section.extra.categorized:

  • categorized = false (current) — flat list of posts sorted by date
  • categorized = true — posts grouped by their first category

post.html — Individual Post

The most complex template. It handles:

  1. Syntax highlighting CSS — loads giallo-light.css or giallo-dark.css based on theme
  2. KaTeX math — only loaded when page.extra.math = true (keeps pages lightweight)
  3. Table of contents — auto-generated sidebar from h2/h3 headings
  4. Back-to-top button — appears on scroll
  5. Back navigation← Posts link
  6. Post metadata — publish date, update date, tags with links
  7. Series link — “Part of series: Building My Website” with clickable link
  8. Outdate alert — configurable warning for old posts
  9. Post content — the rendered markdown
  10. Reactions & comments — both disabled currently

The series link (lines 117-124) is the most significant customization. Serene doesn’t natively display series information on posts. This block checks if a post has a series taxonomy and renders a link to the series listing page.

{% if page.taxonomies.series is defined %}
<div id="series-info" style="margin-top: 0.5em; font-size: 0.9em;">
  {% for s in page.taxonomies.series -%}
  {% set series_slugify = s | slugify -%}
  Part of series: <a class="instant" href="{{ config.base_url ~ '/series/' ~ series_slugify }}">{{ s }}</a>
  {%- endfor %}
</div>
{% endif %}

series/ — Fully Custom Templates

Serene has tag templates but no series templates. These were created from scratch, modeled after the tag templates:

  • series/list.html — Renders at /series/. Shows all series names as links.
  • series/single.html — Renders at /series/building-my-website/. Lists all posts in a specific series with titles and dates.

Both use the same Tera template inheritance ({% extends "_base.html" %}), block structure, and CSS classes as the theme’s tag templates so they blend in visually.

tags/ — Modified Theme Templates

These override Serene’s tag templates with one change: descriptive back navigation.

  • tags/list.html: back link goes ← Home (instead of generic)
  • tags/single.html: back link goes ← Tags (instead of generic)

Static Assets

FilePurpose
static/giallo-light.cssSyntax highlighting colors for light mode
static/giallo-dark.cssSyntax highlighting colors for dark mode

These exist because zola.toml sets style = "class" for syntax highlighting. Zola wraps code tokens in CSS classes, and these stylesheets provide the colors. The Serene theme’s JavaScript swaps between them when the user toggles dark/light mode.

sass/ — Style Overrides

Currently empty (contains only .gitkeep). To override Serene’s styles, create .scss files here matching the theme’s sass file names. Zola compiles yours instead of the theme’s.

Writing a Post

Quick Start

  1. Create a new .md file in content/posts/ using the naming convention YYYY-MM-DD-post-slug.md
  2. Add the frontmatter (see template below)
  3. Write your content in markdown
  4. Run zola serve to preview
  5. Push to GitHub to deploy

File Naming Convention

Post files use a date prefix for easy chronological sorting:

content/posts/2026-02-11-building-my-learnbase-mvp.md
content/posts/2026-03-15-some-other-post.md

The date in the filename is for your convenience only — the slug field in frontmatter controls the actual URL, and the date field controls sort order. The filename itself doesn’t affect the published site.

Frontmatter Template

Copy this to start a new post:

+++
title = "Post Title"
slug = "post-title"
date = 2026-01-01
draft = false

[taxonomies]
tags = ["tag1", "tag2"]
series = ["Series Name"]      # Optional

[extra]
series_order = 1              # Optional, position in series
+++

See Frontmatter Fields for the full field reference.

Writing Tips

Headings

Use ## (h2) and ### (h3) for section headings. These automatically appear in the table of contents sidebar. Don’t use # (h1) — the post title is already rendered as h1 by the template.

Code Blocks

Fenced code blocks with language hints get syntax highlighting:

```rust
fn main() {
    println!("Hello, world!");
}
```

A “copy” button appears automatically on code blocks (controlled by the copy = true setting in the blog section config).

Images

Place images in the same directory as the post or in static/:

![Alt text](image.png)

Images in static/ are referenced from the site root: ![Alt text](/images/photo.png).

Drafts

Set draft = true in frontmatter to hide a post from listings and feeds. It won’t appear on the site but will still be accessible by direct URL during local development.

Escaping Tera Template Syntax

If you write a post that includes Tera template code (e.g., documenting how your templates work), you must escape the {{ }} and {% %} syntax. Zola processes these as shortcodes/template directives even inside markdown code blocks.

Escape rules:

  • Use {{/* and */}} instead of {{ and }}
  • Use {%/* and */%} instead of {% and %}

For posts with many template code blocks, it may be more practical to describe the changes and link to the full files in the repository rather than inlining the entire template content.

See the Zola shortcodes documentation for details.

Content Format

Posts follow a two-part format:

  1. Reflections/commentary at the top — what you learned, why it matters, personal takeaways
  2. Tutorial-style steps below — reproducible instructions others (or an AI) can follow

Reflections Section

The reflections section is always written by the human author. When an LLM or AI tool is helping to generate or scaffold a post, the reflections section should be left blank with a placeholder comment for the author to fill in later:

## Reflections

<!-- TODO: Write reflections/commentary section -->

This section is where the personal voice lives — it’s not something that should be generated.

Tutorial Section

The tutorial section should be detailed enough that a human or AI could follow the steps to reproduce the project from scratch. Include exact commands, file contents, version numbers, and assumptions about the environment.

This format is informal and will evolve with use.

Using aipack for Post Generation

The aipack tool can generate post files from prompts. The pro@coder agent with knowledge_globs pointing to the frontmatter template works well for scaffolding posts.

# Preview (dry run)
aip run pro@coder -f "Create a blog post about X" --write_mode false

# Write the file
aip run pro@coder -f "Create a blog post about X" --write_mode true

Cost: approximately $0.03/run with Gemini Pro.

Creating a Series

Series group related posts into a multi-part sequence. They’re implemented using Zola’s taxonomy system.

How to Add a Post to a Series

In the post’s frontmatter, add the series name and order:

[taxonomies]
series = ["Building My Website"]

[extra]
series_order = 1
  • Series name uses proper case in frontmatter (e.g., “Building My Website”). Zola auto-slugifies it for URLs → /series/building-my-website/.
  • series_order determines the position within the series (1, 2, 3…).

What Zola Generates Automatically

When at least one post references a series, Zola creates:

PageURLContent
Series index/series/Lists all series names
Series detail/series/building-my-website/Lists all posts in that series

These pages use the custom templates in templates/series/.

What Appears on Post Pages

The post.html template checks if a post belongs to a series and displays:

Part of series: Building My Website

This appears below the post’s tags, linking readers to the full series listing.

Creating a New Series

No configuration is needed — just use a new series name in a post’s frontmatter:

[taxonomies]
series = ["New Series Name"]

Zola automatically creates the taxonomy pages. The series will appear on /series/ as soon as at least one published (non-draft) post references it.

Series Name Conventions

  • Use proper case: "Building My Website" not "building-my-website"
  • Keep names consistent across posts — exact string match is required
  • The URL slug is auto-generated: "Building My Website"/series/building-my-website/

Customizing the Theme

The site uses the Serene theme, installed as a git submodule. Customizations are made by overriding theme files, not editing the theme directly.

The Override Pattern

Zola checks your project’s directories first, then falls back to the theme:

templates/blog.html        ← Zola uses this (your override)
themes/serene/templates/blog.html  ← Ignored when override exists

To customize any theme template:

  1. Find the original in themes/serene/templates/
  2. Copy it to the same relative path in your project’s templates/
  3. Modify your copy

The theme’s original stays untouched, so git submodule update --remote can pull theme updates without conflicts.

Template Customization

Modifying an Existing Template

Example: changing the back link text on the blog page.

  1. The theme’s blog.html has a generic back link
  2. Copy themes/serene/templates/blog.htmltemplates/blog.html
  3. Change the back link:
<a id="back-link" href="{{ get_url(path="/") }}">← Home</a>

Adding a New Taxonomy Template

Serene provides tags/ templates but no series/ templates. To add series support:

  1. Create templates/series/list.html and templates/series/single.html
  2. Model them after the existing tags/ templates
  3. Use the same {% extends "_base.html" %} pattern and CSS classes

The templates will automatically be used for URLs matching /series/ and /series/<name>/.

Style Customization

SCSS Overrides

The sass/ directory is currently empty. To override Serene’s styles:

  1. Find the SCSS file in themes/serene/sass/
  2. Create a file with the same name in your sass/ directory
  3. Zola compiles yours instead of the theme’s

Inline Styles

For small, one-off tweaks, inline styles work in templates:

<div id="series-info" style="margin-top: 0.5em; font-size: 0.9em;">

This is acceptable for minor additions but should be moved to SCSS as customizations grow.

Theme Features (Controlled via Config)

These Serene features are toggled in content/posts/_index.md under [extra]:

FeatureSettingCurrent
Table of contentstoctrue
Code copy buttoncopytrue
Comments (Giscus)commentfalse
Outdate alertoutdate_alertfalse

Site-wide features are in zola.toml under [extra]:

FeatureSettingCurrent
Dark mode toggleforce_theme = falseEnabled
Emoji reactionsreactionfalse
Footer creditsfooter_creditstrue

Updating the Theme

# Pull latest changes from Serene
git submodule update --remote themes/serene

# Test locally
zola serve

# If everything works, commit the submodule update
git add themes/serene
git commit -m "Update Serene theme"

Caution: If Serene changes the structure of a template you’ve overridden, your override may break. Always test locally after updating.

Frontmatter Fields

Every post requires a TOML frontmatter block between +++ markers at the top of the file.

Required Fields

FieldTypeDescriptionExample
titleStringPost title (displayed on page and in listings)"Hello World"
slugStringURL path segment — never change once published"hello-world"
dateDatePublication date2026-02-04

Optional Fields

FieldTypeDefaultDescription
draftBooleanfalseSet true to hide from listings and feeds
updatedDateLast updated date (shown if different from date)
descriptionStringUsed for meta description tag (SEO)
summaryStringShort summary, used in meta tags if set

Taxonomies

Declared under [taxonomies]:

FieldTypeDescription
tagsArray of stringsTopic labels
seriesArray of stringsMulti-part post grouping
categoriesArray of stringsBroad categories (not actively used)
[taxonomies]
tags = ["rust", "zola", "web"]
series = ["Building My Website"]

Extra Fields

Declared under [extra]:

FieldTypeDefaultDescription
series_orderIntegerPosition within a series (1, 2, 3…)
tocBoolean(inherits from section)Override table of contents for this post
commentBoolean(inherits from section)Override comments for this post
outdate_alertBoolean(inherits from section)Override outdate alert for this post
outdate_alert_daysInteger(inherits from section)Override days threshold
mathBooleanfalseEnable KaTeX math rendering
mermaidBooleanfalseEnable Mermaid diagrams
featuredBooleanfalseHighlight in post listings
copyBoolean(inherits from section)Override code copy button

Full Example

+++
title = "Building My Website — Part 1"
slug = "building-my-website-part-1"
date = 2026-02-10
draft = false

[taxonomies]
tags = ["rust", "zola", "web"]
series = ["Building My Website"]

[extra]
series_order = 1
+++

Notes

  • The slug determines the URL: /posts/<slug>/. Changing it after publication breaks existing links.
  • The title can be changed freely — it doesn’t affect URLs.
  • Fields under [extra] that say “inherits from section” get their default from content/posts/_index.md. You only need to set them per-post if you want to override the section default.

Site Configuration

All site configuration lives in zola.toml at the project root.

Core Settings

base_url = "https://mylearnbase.com"
title = "My Learn Base"
description = "A personal learning journal and portfolio"
default_language = "en"
theme = "serene"
FieldPurpose
base_urlUsed to generate all absolute URLs (RSS, sitemaps, canonical links)
titleBrowser tab title, RSS feed title
descriptionDefault meta description for pages that don’t set their own
themeWhich theme directory to use (under themes/)

Build Settings

compile_sass = true
minify_html = false
build_search_index = false
generate_feeds = true
feed_filenames = ["rss.xml"]
FieldPurposeCurrent
compile_sassCompile .scss files into CSSEnabled
minify_htmlCompress HTML outputDisabled (easier to debug)
build_search_indexGenerate client-side search indexDisabled
generate_feedsGenerate RSS/Atom feedsEnabled
feed_filenamesOutput filenames for feedsrss.xml

Taxonomies

taxonomies = [{ name = "tags" }, { name = "categories" }, { name = "series" }]

Each entry tells Zola to look for this field in post frontmatter and auto-generate listing pages. Each taxonomy needs matching templates in templates/<taxonomy_name>/.

Markdown Processing

[markdown]
external_links_target_blank = false
external_links_no_follow = true
external_links_no_referrer = true
smart_punctuation = false
FieldPurpose
external_links_target_blankOpen external links in new tab
external_links_no_followAdd rel="nofollow" to external links (SEO)
external_links_no_referrerAdd rel="noreferrer" to external links (privacy)
smart_punctuationConvert "quotes" to curly quotes, -- to em dash

Syntax Highlighting

[markdown.highlighting]
style = "class"
light_theme = "github-light"
dark_theme = "catppuccin-mocha"

style = "class" means code tokens get CSS classes instead of inline styles. This enables dynamic light/dark switching via the CSS files in static/ (giallo-light.css, giallo-dark.css).

URL Slugification

[slugify]
paths = "on"
taxonomies = "on"
anchors = "on"

Controls automatic URL-safe conversion. With all set to "on":

  • /posts/My Post Title/posts/my-post-title
  • Series “Building My Website” → /series/building-my-website
  • ## My Heading#my-heading

Theme-Specific Settings ([extra])

[extra]
sections = [{ name = "posts", path = "/posts", is_external = false }]
blog_section_path = "/posts"
back_link_text = "Back"
force_theme = false
footer_copyright = "© 2026"
footer_credits = true
not_found_error_text = "404 Not Found"
not_found_recover_text = "« back to home »"
reaction = false

These are not read by Zola itself — they’re a contract between your templates and the Serene theme. The theme’s templates check these values with {% if config.extra.reaction %} style conditionals.

FieldPurpose
sectionsNavigation menu entries
blog_section_pathTells Serene where the blog section lives
force_themeLock to light or dark (false = allow toggle)
footer_copyrightCopyright text in footer
footer_creditsShow “Powered by Zola & Serene”
reactionEnable emoji reactions on posts

Cloudflare Deployment

Setup Summary

The site is deployed on Cloudflare Pages, connected to the GitHub repository. Every push to main triggers a rebuild and deploy.

Build Configuration

SettingValue
Framework presetNone (custom)
Production branchmain
Build commandSee below
Build output directorypublic

Build Command

curl -sL https://github.com/getzola/zola/releases/download/v0.22.1/zola-v0.22.1-x86_64-unknown-linux-gnu.tar.gz | tar xz && ./zola build

Cloudflare Pages no longer pre-installs Zola, so the build command downloads it first. This adds a few seconds but is reliable.

To update Zola version: Change the version number in the URL (both the directory name and the tarball name).

Custom Domain

SettingValue
Domainmylearnbase.com
DNS providerCloudflare (migrated from Porkbun)
HTTPSAutomatic via Cloudflare

The domain’s nameservers were migrated to Cloudflare to enable tight integration with Pages. HTTPS certificates are provisioned and renewed automatically.

Known Issues

CSS Missing on Preview URLs

Cloudflare generates preview URLs for branches (e.g., abc123.mylearnbase.pages.dev). These may show broken styling because:

  1. zola.toml sets base_url = "https://mylearnbase.com"
  2. Zola generates absolute URLs for CSS based on base_url
  3. The preview URL (*.pages.dev) doesn’t match, so CSS paths break

Workaround: Use zola serve locally for visual verification instead of preview URLs.

Build Failures After Zola Updates

If a new Zola version introduces breaking changes:

  1. Pin to the known-working version in the build command (currently v0.22.1)
  2. Test the new version locally with zola build before updating the build command
  3. Update the version in the build command only after local verification

Monitoring

Cloudflare Pages dashboard shows:

  • Build logs (stdout/stderr from the build command)
  • Deploy history with rollback capability
  • Bandwidth and request metrics

No additional monitoring is configured.