Welcome to Web World Wide, a high-performance, $0/month, self-hosted blog stack designed for Raspberry Pi. It replaces bloated, database-heavy platforms (like Ghost or WordPress) with a hyper-fast static site generator and a lightweight Node.js admin panel.
🌐 Live site → webworldwide.online
See CONTRIBUTING.md for local development, the quality pipeline, and branch-protection setup.
A fresh clone runs the entire stack — Astro, the admin CMS, Remark42, Umami, and Postgres — on a laptop (Windows, macOS, or Linux) in two commands.
Requires: Node 22+ and Docker. Start Docker before running the dev command.
| Platform | Docker option(s) |
|---|---|
| Windows | Docker Desktop (with WSL2 backend recommended) |
| macOS | Docker Desktop, OrbStack, or Colima — any one works |
| Linux | Docker Engine (apt install docker.io or distro equivalent) — start with sudo systemctl start docker |
git clone https://github.com/WebWorldWide/webworldwide-website
cd webworldwide-website
npm install # cascades into site/ and admin/ on first run
npm run dev # preflight → docker + astro + admin in parallelThe same two commands work identically on Windows (PowerShell or Git
Bash), macOS, and Linux. npm run dev shells through
npm-run-all2/run-p, which uses platform-native parallel execution
on all three; no bash-isms in any npm script.
The first npm install takes a few minutes (pulls Astro, React, Three.js,
TipTap, better-sqlite3 prebuilt binaries). Subsequent runs are fast.
npm run dev runs a preflight that auto-creates docker/.env.dev from
.env.dev.example and verifies Docker is reachable — if Docker isn't
running it tells you so and exits cleanly.
Open:
- Public site: http://localhost:4321
- Admin: http://localhost:3000 (log in:
admin/password) - Comments (Remark42): http://localhost:8081 (admin user:
admin) - Analytics (Umami): http://localhost:3001 (configure on first visit)
Operational scripts:
npm run dev:check— ping every service, print a status table, non-zero on any failurenpm run db:seed— create the admin user (admin/password) and 5 sample media rowsnpm run db:reset— wipe the local DB and dev uploads, then re-seed (prompts unless--yes)npm run dev:stop— shut down the Docker servicesnpm run dev:site/npm run dev:admin— run just the Astro site or just the admin (no Docker)
WebAuthn uses rpID=localhost in dev, so passkeys work without HTTPS on
every browser. Register one from Settings → Security after first login.
- Site Generator: Astro 5 (compiles Markdown + React islands into ultra-fast static HTML)
- CMS Admin: Custom Node.js/Express Dashboard with WebAuthn (Passkeys)
- Analytics: Umami (Self-hosted privacy-friendly analytics via PostgreSQL)
- Comments: Remark42 (Self-hosted privacy-focused commenting engine)
- Reverse Proxy: Caddy (Automatic HTTPS and routing)
- Tunneling: Cloudflare Tunnel (Exposes your Pi to the internet securely without port-forwarding)
The full stack ships everything a personal blog needs out of the box. Every capability has a CONTRIBUTING.md section explaining how it's wired and how to extend it.
| Capability | What it gives you | Where it's documented |
|---|---|---|
| Local development | One-command full stack (Astro + admin + Remark42 + Umami + Postgres) | Local development |
| Passkey auth | WebAuthn passkeys for passwordless admin login (Touch ID / Face ID / Windows Hello) | Passkeys in local dev |
| Block editor | TipTap + CodeMirror with slash commands, tables, callouts, math, footnotes, code highlighting, find & replace | Editor shortcuts |
| Block types | Headings, lists, blockquotes, tables, callouts, KaTeX math, footnotes, code blocks with syntax highlighting | Editor block types |
| Media library | Drop any file — auto-converts images (AVIF/WebP/responsive srcset), video, audio, PDFs, archives, code | Testing the conversion pipeline |
| Authoring extras | Scheduled publishing, draft preview links, per-post custom CSS/JS, cover images, redirects, activity log | Phase 5e — CMS authoring extras |
| Embeds | Paste-to-embed for YouTube, Vimeo, Bluesky, Mastodon, CodePen, Gist, Spotify, SoundCloud, TikTok + generic OG | Phase 7 — embeds |
| Fediverse | h-card / h-entry microformats, webmention receiver, Bridgy Fed federation, Mastodon-style replies | Phase 8 — Fediverse federation |
| Comments | Unified moderation queue (Remark42 + webmentions + Bluesky) with SSE live updates and one-tap reply | Phase 8.5 — unified comment moderation |
| Cross-post (POSSE) | Auto-post to Bluesky + Mastodon on publish — one post + a rich link card — configured in Settings → Syndication; Bluesky replies mirror into the moderation queue | Phase 9 — Bluesky cross-post |
| Accessibility (WCAG 2.2 AA) | Skip links, focus traps, contrast tokens, motion respect, status independence, axe-core in CI | Accessibility |
| Performance | Inline critical CSS, fingerprinted JS + SRI, responsive images, lazy embeds, CSP, Lighthouse gates | Performance |
The first push to main triggers deploy.yml (already wired). Before that,
read MIGRATION.md for the post-merge steps: GitHub branch
protection, Bluesky / SMTP / Bridgy Fed credentials, and the two cron entries
that drive scheduled publish + webmention dump.
This stack stands on the shoulders of:
Astro (static site engine + React islands), TipTap + ProseMirror (editor), CodeMirror (raw markdown / code panes), KaTeX (math), Express + better-sqlite3 (admin backend), Bridgy Fed (Fediverse bridge), Remark42 (comments), Umami (analytics), Caddy (HTTPS + reverse proxy), Cloudflare Tunnel (secure ingress), @atproto/api (Bluesky / AT Protocol), axe-core + Playwright (a11y + e2e), Vitest + node:test (unit tests), Lighthouse CI (perf budget).
- You access the Admin CMS (
admin.yourdomain.com) from your phone or laptop using Touch ID / Face ID. - You write a post using the WYSIWYG editor and hit
Save. The post is saved as a.mdfile on the Raspberry Pi. - You click
[PUBLISH SITE]. The CMS commits the markdown files to GitHub. - GitHub Actions automatically builds the Astro site and deploys it to GitHub Pages for free, global CDN hosting.
- Visitors view your ultra-fast site while Umami and Remark42 handle analytics and comments via the Cloudflare Tunnel.
- A Raspberry Pi (or any Linux server)
- A Cloudflare account with a Domain name
- A GitHub account and a Personal Access Token (PAT)
- Create a Cloudflare Tunnel in Zero Trust.
- Add Public Hostnames pointing to
http://caddy:80for:admin.yourdomain.comcomments.yourdomain.comanalytics.yourdomain.com
SSH into your fresh Raspberry Pi OS Lite (64-bit) and run:
sudo apt-get update -y && sudo apt-get install -y git
sudo git clone https://github.com/WebWorldWide/webworldwide-website.git /opt/web-world-wide
sudo /opt/web-world-wide/scripts/bootstrap.shThe script is idempotent — re-running on an already-set-up Pi prints "all phases healthy" in under 30 seconds. On a fresh Pi it:
- Verifies arch, OS, disk, network connectivity (fail-fast).
- Installs Docker, Node 22, and required apt packages.
- Sets up a 2 GB swapfile.
- Prompts for your Cloudflare Tunnel token and GitHub PAT (with
--cf-token=and--gh-pat=flag overrides for scripted runs). - Validates the Cloudflare token against the Cloudflare API in under 5 seconds.
- Generates random secrets, creates
docker/.env, brings the stack up. - Installs systemd boot-check + cron jobs (backups, auto-update, maintenance).
- Polls every service with backoff until all healthy, then prints a status table.
- Generates the age-encrypted backup keypair and pushes the public key to
www-blog-backups(creates the repo automatically if your PAT hasreposcope). - Prints the age private key last — save it to a password manager before closing the SSH session.
Expected runtime on a Pi 5 with good network: under 6 minutes from sudo ./bootstrap.sh to passkey-registration prompt.
- Go to
admin.yourdomain.com - Create your first admin account.
- Once logged in, click "Register Passkey" to bind your device (Face ID / Touch ID) for instant passwordless logins.
The bootstrap.sh script automatically sets up daily automated backups of your SQLite Auth DB, PostgreSQL analytics, and Remark42 comments. These are encrypted using age and pushed to a private www-blog-backups repository.
Enjoy your blazingly fast, fully-owned piece of the internet!