Skip to content

Cloudflare Pages (homelab docs)

How homelab documentation is built and published to Cloudflare Pages.

Live site: hldocs-c0acdec9.pages.dev


Overview

Item Value
Source docs/ + mkdocs.yml in homelab repo
Build mkdocs-material, mkdocs build --strict
CI .github/workflows/docs.yml
Runner Selected by repository variable CI_RUNS_ON; see central runner management
Python actions/setup-python@v7, Python 3.13
Node tooling actions/setup-node@v7, Node 22, npm ci for markdownlint
Action runtime FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true while the repo completes the Node 24 transition
Deploy action cloudflare/wrangler-action@v4
Pages project hldocs-c0acdec9
Trigger Push to main for docs, documentation checks, site config, or their dependency locks; also workflow_dispatch
Secrets GitHub CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID

The GitHub repository is private; the Pages site is public. Links to repository manuals require GitHub access. Those manuals are not automatically copied to the public site. Review the exact contents before moving any additional source into docs/.

Docs CI is separate from Traefik’s Cloudflare DNS token (services/traefik/.env.sops.yaml). Use a Pages-scoped API token for GitHub Actions; keep Traefik DNS-01 on its own token (see Public edge DR).

The Pages site is intentionally public as of 2026-06-26. Do not publish plaintext secrets, private host keys, private IP credentials, or unredacted incident artifacts. Contractor assessments and review reports may be published under docs/reviews/ when they contain links/evidence but no sensitive material.


Local preview

From repo root:

uv sync --locked
npm ci
uv run mkdocs serve          # http://127.0.0.1:8000
uv run python scripts/check-docs.py
uv run mkdocs build --strict # same check as CI — must pass before merge
uv run python scripts/check-docs.py --site-dir site
uv run python scripts/lint-markdown.py

Markdown is linted in CI via npm ci + scripts/lint-markdown.py. Use uv run python scripts/lint-markdown.py --fix before committing docs changes.


Publish pipeline

  1. Merge a reviewed PR to main. The shared checkout and main are production inputs.
  2. Deploy Docs workflow runs:
  3. actions/checkout@v7 (pinned SHA in workflow)
  4. actions/setup-python@v7 with Python 3.13
  5. actions/setup-node@v7 with Node 22
  6. npm ci
  7. python scripts/lint-markdown.py
  8. pip install uv
  9. uv sync --locked (the same uv.lock used locally; no separate CI-only Material pin)
  10. uv run python scripts/check-docs.py
  11. uv run mkdocs build --strict
  12. uv run python scripts/check-docs.py --site-dir site
  13. Deploy with cloudflare/wrangler-action@v4: pages deploy site/ --project-name=hldocs-c0acdec9 --commit-dirty=true
  14. Confirm green run: Actions → Deploy Docs.
  15. Run uv run python scripts/check-docs.py --site-dir site --live-url https://hldocs-c0acdec9.pages.dev from the exact built revision. This compares every expected route with the live sitemap and the searchable page content. A local build passing does not establish that production was updated.

--strict fails on warnings. mkdocs.yml promotes missing navigation entries, broken heading anchors, and unrecognized relative links to warnings, so these are also merge blockers. Link to repo files with GitHub blob URLs, not ../../services/... or ../../scripts/... paths.

The workflow intentionally separates Node concepts:

  • setup-node installs Node 22 for repo-local npm tooling (markdownlint-cli2 currently requires Node >=22).
  • FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true exercises GitHub JavaScript actions on Node 24 during the platform transition.
  • Pages project hldocs-c0acdec9 is assumed to already exist; the workflow only deploys. Create/list steps are not part of CI anymore.

Adding pages to navigation

Edit mkdocs.yml nav:. Every Markdown page under docs/ must appear exactly once; the source checker rejects omitted pages, duplicate routes, and duplicate labels within a group. The strict build also rejects missing targets and broken anchors.

Choose the section by what the reader needs, not by the source directory:

Section Contents
Home Task shortcuts and the repository project map
Runbooks Operating procedures grouped by task
Infrastructure Network, compute, platform design, hosts, and appliances
Services Service guides, operator manuals, and customer apps
Security Risk register and operator handover
History Journals, dated scans, reviews, postmortems, and retired systems
  • Add a runbook under the appropriate task group and to the runbook directory.
  • Add journals under History → Journal → month, newest first, and to the journal index. Keep journal/index.md first in its navigation group.
  • Put reviews under History → Reviews and audits. Keep a package README with its executive summary and links.
  • Move retired pages into the relevant History group, keeping the original file path and URL.
  • Include capture dates in scan labels. Do not label a historical snapshot simply “live.”
  • Put section index pages first. Keep navigation.tabs and navigation.indexes enabled; do not restore navigation.expand, which opens the entire tree by default.

Do not publish scratch files or duplicate copies to make an omitted-page check pass. Resolve their ownership before adding, moving, or deleting them. See History for the archive policy.


Optional hardening

Task Status Notes
Pages deploy via GitHub Actions ✅ Done Secrets in repo settings
Cloudflare Access on docs URL ❌ Declined Owner accepted public Pages site (2026-06-26)

Troubleshooting

Deploy Docs failed on mkdocs build --strict

  • Read the log for WARNING lines (strict treats them as errors).
  • Common fixes:
  • Replace ../../services/... / ../../scripts/... links with https://github.com/spadoople/homelab/blob/main/...
  • Fix stale #anchor links after heading renames.
  • Reproduce locally: uv run mkdocs build --strict.

Node or Wrangler errors

  • Confirm the job is using actions/setup-node@v7 with Node 22; that controls npm tooling, not the JavaScript action runtime.
  • Keep FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true unless the Node 24 transition has been retired across all workflows.
  • Wrangler deploy failures are usually token scope or project name mismatches — confirm CLOUDFLARE_API_TOKEN can edit Pages and the project is hldocs-c0acdec9.

Pages project missing

The workflow does not auto-create the project. If deploy fails because the project is absent, create hldocs-c0acdec9 once in the Cloudflare dashboard (or via Wrangler CLI) with production branch main, then re-run Deploy Docs. Token needs Account → Cloudflare Pages → Edit.

Site stale after green deploy

Hard-refresh or check deployment in Cloudflare dashboard → Workers & Pages → hldocs-c0acdec9 → Deployments.