Stanton Web Applications - Blog

Stanton Web Applications - Blog

Decentralized. Sovereign. Free.

How I Built a Decentralized CMS with Nostr + GitHub Actions

Published: June 08, 2025 at 08:45 PM PDT   |   Updated: June 08, 2025 at 08:49 PM PDT

Hero image

This article walks through how I built a fully decentralized blog using Nostr as the backend CMS, GitHub Actions for automation, and GitHub Pages for free global hosting. No servers, no logins — just sovereign publishing on open protocols.

#blog#article#nostr#cms#decentralized web#github actions#github pages#bitcoin#open source#permissionless#proof of work#blogging#

How 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 (like relay.damus.io, relay.primal.net, nostr.mom, etc.) and fetches any articles I've written using my public key. Only posts tagged with blog or article are kept.

Each article is:

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 read articles/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:

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.