-
@ Andrew G. Stanton
2025-06-09 03:49:17How I Built a Decentralized CMS with Nostr + GitHub Actions
🧡 My first post on a fully sovereign blog.
Introduction
This blog post isn’t hosted on Medium, Substack, or WordPress.\ It doesn’t live on a database I don’t control.\ There’s no login, no admin panel, no SaaS dashboard.
Instead, this post was published as a Nostr event —\ stored on dozens of relays,\ fetched with open-source scripts,\ rendered as a static HTML file,\ and served globally via GitHub Pages.
And it all runs without a single server I have to manage.
Let me show you how it works — and why this matters.
Step 1: Writing on Nostr
I use Primal.net to write my articles.\ Their long-form editor lets you add titles, summaries, and tags to a special kind of Nostr event (
30023
).\ You just click publish — and the article propagates across the Nostr network.Step 2: Fetching Events
On my GitHub repo, I maintain a script called
fetch_articles.py
.\ It connects to multiple Nostr relays (likerelay.damus.io
,relay.primal.net
,nostr.mom
, etc.) and fetches any articles I've written using my public key.\ Only posts tagged withblog
orarticle
are kept.Each article is:
-
Deduplicated
-
Parsed for title, summary, image, tags, and content
-
Converted from Markdown to clean HTML
-
Saved in a static folder
Step 3: Hosting with GitHub Pages
The output goes straight into the
docs/
folder of my public GitHub repository.\ Thanks to GitHub Pages, the site is instantly deployed as a static website.The homepage (
index.html
) uses JavaScript to readarticles/index.json
and display the 10 most recent blog posts — each linking to its full static HTML page.Step 4: Fully Automated via GitHub Actions
To keep things fresh, I created a GitHub Action called
Fetch and Build Articles
.\ It runs daily — or whenever I trigger it manually — and fetches new content from Nostr, updates the site, and redeploys everything.No databases.\ No plugins.\ No backend headaches.\ Just content — and the open protocols that carry it.
Why This Matters
Most blogs are brittle.\ Lose your password, your server, or your platform — and your voice disappears.
This setup flips that on its head:
-
I own my content — It's stored on a public, censorship-resistant network.
-
Anyone can verify it — The data lives on Nostr relays, signed with my pubkey.
-
It costs nothing to host — GitHub Pages serves everything statically.
-
It’s future-proof — If GitHub disappeared, I could mirror the repo anywhere.
This is what publishing should look like in 2025.
Want to Build Your Own?
You can fork the repo I use here —\ or read the code and set it up for your own Nostr pubkey.
If you’re not on Nostr yet, you can find me at:\ 🧬
npub19wvckp8z58lxs4djuz43pwujka6tthaq77yjd3axttsgppnj0ersgdguvd
This is just the beginning.\ One post, one block, one step at a time —\ on our own terms.
-