File-based markdown publishing CMS with hierarchical sections, server-rendered HTML, and no editorial database.
Extracted from a production file-based publishing platform.
- Markdown + YAML frontmatter — git-trackable content in
content/blog/ - Hierarchical sections — nested folders and
/section/:keyURLs - Search, author pages, RSS, sitemap
- Tag-based related posts and optional content linker (internal link injection)
- Read-finder widget (client-side article discovery)
- IndexNow hooks (optional, env-configured)
- Email-gated reports — SQLite capture + optional AWS SES PDF delivery
git clone https://github.com/YOUR_USER/markdisk-cms.git
cd markdisk-cms
npm install
npm startEdit config.js or set environment variables (see .env.example):
| Option | Env var | Default |
|---|---|---|
| Port | PORT |
3080 |
| Base URL | BASE_URL |
http://localhost:3080 |
| Site name | SITE_NAME |
Markdisk |
| IndexNow key | INDEXNOW_KEY |
(disabled) |
| IndexNow host | INDEXNOW_HOST |
(disabled) |
| SES from | SES_FROM_EMAIL |
(optional) |
Posts live under content/blog/{category}/{subcategory}/:
---
title: "My Article"
slug: my-article
date: 2026-07-01
author: Alex Morgan
excerpt: Short listing description.
section: guides/tutorials
tags: ["CMS", "Tutorial"]
---Optional editorial CSS classes: .article-takeaway, .article-news (see demo posts).
emailGate: true
leadMagnetPdf: demo.pdfPlace PDFs in data/lead-magnets/pdfs/. Signups go to SQLite; configure AWS SES env vars to email download links.
| Route | Description |
|---|---|
/ |
Homepage |
/section/:key |
Section listing (supports parent/child keys) |
/:section/:slug or /:section/:sub/:slug |
Article |
/author/:slug |
Author profile |
/search |
Full-text search |
/feed.xml |
RSS |
/sitemap.xml |
Dynamic sitemap |
/api/read-finder-index.json |
Read-finder metadata API |
Audit and apply internal links:
npm run audit:links
node scripts/apply-pillar-internal-links.mjsManifest: data/internalLinks.json
- Never commit
.envfiles, SQLite signup databases (*.sqlite), or production PDFs..gitignoreblocks these by default. - AWS credentials are read from the standard SDK chain (env vars or
~/.aws/credentials). Do not hardcode them in source. - IndexNow keys belong in environment variables only. When enabled, the key is served publicly at
/{key}.txtfor search-engine verification — that is expected, but the key must not appear in committed code. - Debug routes (
/indexnow,/indexnow-verify-key, etc.) are disabled by default. SetENABLE_DEBUG_ROUTES=trueonly for local troubleshooting.
GPL-3.0 — see LICENSE.