Skip to content

Site runbook

How this site is built, how to add to it, and what to do when it breaks.


What's actually running

Five moving parts, no servers of your own:

Part Where Job
Markdown files docs/ The notes themselves
mkdocs.yml repo root Site config and sidebar order
theme.css docs/stylesheets/ Colours, fonts, custom blocks
requirements.txt repo root Tells Cloudflare what to install
Cloudflare Pages cloud Rebuilds and hosts on every push

The flow: write markdown → git push → Cloudflare runs mkdocs build → static HTML lands on the CDN. Nothing is dynamic, nothing has a database.

site/ is generated output. It's gitignored and should stay that way.


Daily workflow

Open two terminals.

Terminal 1 — live preview. Leave running while you write:

cd ~/shan-network-blog
source .venv/bin/activate
mkdocs serve

Browser at localhost:8000. Saves reload automatically.

Terminal 2 — git. When a note's worth keeping:

git add -A
git commit -m "notes: netconf capabilities exchange"
git push

Cloudflare picks it up within a minute or two.

The venv

source .venv/bin/activate is needed in every new terminal. If mkdocs says command not found, that's almost always why. The prompt shows (.venv) when it's active.


Adding a new page

Two steps, and the second is the one that gets forgotten.

1. Create the file under the right folder in docs/:

code docs/apis/ansible-vault.md

Start it with frontmatter and an H1:

---
status: draft
---

# Ansible Vault

Encrypting secrets so `ansible_password` never sits in plaintext.

2. Add it to nav: in mkdocs.yml, under the section it belongs to:

  - 2.0 APIs and protocols:
      - IOS-XE with Ansible: apis/ansible-ios.md
      - Ansible Vault: apis/ansible-vault.md      # ← new

Paths in nav: are relative to docs/, so it's apis/ansible-vault.md, not docs/apis/ansible-vault.md.

A page not listed in nav: still builds and is reachable by URL — it just won't appear in the sidebar. If a new page doesn't show up, this is why.


Adding a new section

1. Make the folder:

mkdir docs/labs

2. Add at least one page — an empty folder does nothing:

code docs/labs/eve-ng-topology.md

3. Add the section to nav:. Order in the file is order in the sidebar:

nav:
  - Home: index.md
  - 1.0 Foundation:
      - ...
  - Labs:
      - EVE-NG topology: labs/eve-ng-topology.md

Indentation is two spaces per level and YAML rejects tabs outright. If VS Code is inserting tabs, bottom-right status bar → click the indent setting → Convert Indentation to Spaces.


Writing: what the theme gives you

Callout boxes. Built-in types include note, tip, warning, danger, example, plus the custom lab type:

!!! lab "Build it from an empty file"
    No green dot until I can write this playbook with the docs closed.

!!! warning "Exam trap"
    RESTCONF has no candidate datastore. Rollback questions mean NETCONF.

Add ??? instead of !!! to make it collapsible.

Status pills, from theme.css:

- Ansible inventories [mastered]{ .st .mastered }
- Jinja2 templates [shaky]{ .st .shaky }

Tabs, useful for the same task across platforms:

=== "IOS-XE"
    ```yaml
    cisco.ios.ios_config:
    ```

=== "NX-OS"
    ```yaml
    cisco.nxos.nxos_config:
    ```

Code blocks — always tag the language. It drives highlighting and the copy button:

```yaml
- name: Push NTP servers
  cisco.ios.ios_config:
    lines: ntp server 10.10.10.1
```

Links between pages use relative paths ending in .md:

See [RESTCONF vs NETCONF](../device/restconf-vs-netconf.md).

MkDocs rewrites those to real URLs at build and warns if the target doesn't exist — which makes it a free broken-link check.


Deploy

Automatic. git push to main triggers a Cloudflare build.

To watch it: Cloudflare dashboard → Workers & Pages → your project → Deployments. Click any deployment to see the full build log.

Build settings, for reference if they ever need re-entering:

Setting Value
Production branch main
Build command pip install -r requirements.txt && mkdocs build
Build output directory site
PYTHON_VERSION 3.12

To check a build locally before pushing:

mkdocs build --strict

--strict turns warnings into errors, so broken internal links fail the build instead of shipping quietly.


Troubleshooting

mkdocs: command not found

The venv isn't active. source .venv/bin/activate. If it's active and still failing, reinstall: pip install mkdocs-material.

Config value 'site_name': Required configuration not provided

mkdocs.yml is empty or malformed. Check first:

wc -l mkdocs.yml && head -5 mkdocs.yml

Zero lines means a heredoc paste failed silently. Write the file in VS Code rather than pasting a long block into bash — terminals drop lines on big multi-line pastes, and a stray EOF inside the content terminates the block early.

YAML errors on mkdocs serve

The error names the line. In order of likelihood: tabs instead of spaces, wrong indent depth, a missing space after a colon, or an apostrophe in an unquoted string. Quote any value containing : # ' or ".

A page doesn't appear in the sidebar

It's not in nav:. Or the path is wrong — nav: paths are relative to docs/.

Changes don't show in the browser

mkdocs serve only watches docs/. Editing mkdocs.yml needs a restart: Ctrl+C, then mkdocs serve again.

error: src refspec main does not match any

The branch has no commits yet. Commit first, then push:

git add -A && git commit -m "first" && git push -u origin main

! [rejected] main -> main (non-fast-forward)

Local and remote histories have diverged. Check what's on the remote:

git fetch origin && git log --oneline origin/main

If the remote has nothing you want, git push --force origin main. If it has work you need, git pull --rebase first. Force-pushing is only safe because nobody else clones this repo.

command not found running a config file's contents

Config blocks (YAML, CSS, a bare package name) are file contents, not commands. Terminal blocks start with cd, git, mkdocs, pip, echo.

externally-managed-environment from pip

Ubuntu blocks system-wide pip. Always install inside the venv — the fix is source .venv/bin/activate, never --break-system-packages.

Cloudflare build fails: mkdocs: not found

requirements.txt is missing from the repo root, or the build command doesn't install from it. It must be pip install -r requirements.txt && mkdocs build.

Cloudflare build fails on a plugin

The build image's Python may be too old, or the plugin needs git history that Cloudflare's shallow clone doesn't fetch. Check PYTHON_VERSION is 3.12 first; that fixes most of them.

Site builds but looks unstyled

extra_css path is wrong, or theme.css isn't committed. Check:

git ls-files docs/stylesheets/

Custom colours also need primary: custom and accent: custom in the palette config — without those, Material's own rules outrank the override on specificity.


Command cheat sheet

# start work
cd ~/shan-network-blog && source .venv/bin/activate && mkdocs serve

# save work
git add -A && git commit -m "notes: <what>" && git push

# check before pushing
mkdocs build --strict

# what changed
git status --short

# update the theme
pip install --upgrade mkdocs-material

# see what's tracked
git ls-files

If it all goes wrong

The notes are the only irreplaceable part, and they're plain markdown in docs/. Everything else — venv, config, theme, Cloudflare project — can be rebuilt in twenty minutes.

Worst case: copy docs/ somewhere safe, delete the folder, re-clone, and put docs/ back.