Skip to content

joiha-steven/vibeblog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

195 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vibeblog  v1.1.9

An AI-operated personal blog platform. Write and publish from a clean multilingual admin — or hand the keys to an AI agent and let it write, publish, and even deploy for you.


Next.js 16 React 19 TypeScript Tailwind v4 Supabase Vercel Docker MCP License: MIT

🌐 Live demo · Get your own copy · Let an AI run it · Architecture · Roadmap · License

The demo at manhhung.me is the author's personal blog — a live instance to see the platform in action, not a content showcase (ignore what it says, look at how it works).


vibeblog admin dashboard and reading view

✨ What it is

An open-source (MIT), single-owner blog built for people who just want to write. The public site is statically cached so it loads insanely fast on mobile and desktop, and it's tuned around readable typography — a clean reading experience first. Everything is easy to tweak from the admin (palettes, type, menu, fonts) with no hardcoded values anywhere, so you make it yours without touching code.

All the writing happens in a polished /admin (or over MCP). Text lives in Postgres (Supabase on Vercel, or a bundled Postgres when you self-host); binaries (images, files, icons) go through a pluggable storage driver — Vercel Blob by default, or the local filesystem on Docker. No git push to publish, no CMS to wrangle.

Area What you get
🖋️ Editor TipTap 3 + Markdown · responsive sharp images (original + AVIF/WebP variants) · 3-version time machine · 60s autosave
🎨 Look 6 customizable light+dark palettes · one tunable type system (per-role size/leading/tracking, no hardcoded sizes) · upload a custom font per weight
🌍 i18n Admin + site in en · vi · de · ja · zh · ko
🔍 Reading instant local + Postgres full-text search · ToC · related posts · reading time · progress bar
📈 Built-in cookieless analytics (views / visitors / top pages, no PII) · activity log · soft-delete Trash (nothing auto-purges)
🔎 SEO sitemap · RSS · robots.txt · llms.txt · dynamic OG images — all toggleable
💾 Backups one-click full snapshots (DB + all binaries) to Google Drive, scheduled + restore
🤖 MCP a remote endpoint that lets an AI agent write & manage the blog with the same rules as the admin
📱 PWA installable, launches standalone
🔐 Auth NextAuth v5 · Google sign-in · single authorized owner · edge-guarded admin/API
🚀 Deploy Vercel + Supabase (+ Vercel Blob), or self-host with Docker — bundled Postgres + local storage, no cloud — same codebase

Built on Next.js 16 (App Router, React 19, strict TS) + Tailwind v4, deployed on Vercel or self-hosted with Docker.

Who it's for — one person who wants a fast, good-looking, fully self-owned blog, runs it on Vercel + Supabase or self-hosts it with Docker, and likes the idea of letting an AI agent help run it. Not for — multi-author teams / publications needing roles and editorial workflows. vibeblog is single-owner by design (one authorized email); multi-tenant lives in the planned SaaS, not here.


🚀 Get your own copy

Three ways to stand up your own blog — pick one. Each ends with a live site at your domain.

1️⃣  Do it yourself  — ~10 minutes in the dashboards
  1. Fork this repo (so Vercel deploys your copy).
  2. Database — create a Supabase project → SQL Editor → paste scripts/schema.sqlRun (idempotent). Copy the Project URL + service_role key (Settings → API).
  3. Import to VercelAdd New → Project → import your fork.
  4. Blob storeStorage → Create → Blob, connect it to the project. This injects BLOB_READ_WRITE_TOKEN automatically.
  5. Env vars (Settings → Environment Variables — see the table): SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, AUTH_SECRET (npx auth secret), AUTHORIZED_EMAIL, AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET.
  6. Deploy. Then on your Google OAuth client add the redirect URI https://<your-domain>/api/auth/callback/google.
  7. Open https://<your-domain>/admin, sign in as AUTHORIZED_EMAIL, set your title / palette / menu in Settings, and start writing.
2️⃣  Hand it to an AI agent  — Claude, OpenAI Codex, OpenClaw, Hermes…

Give an agent Vercel + Supabase + GitHub access (tokens / CLI / MCP), then paste:

Deploy my own copy of github.com/joiha-steven/vibeblog:
1. Fork the repo to my account.
2. Create a Supabase project and run scripts/schema.sql in its SQL editor.
3. Create a Vercel project from the fork; add a Vercel Blob store (this sets BLOB_READ_WRITE_TOKEN).
4. Walk me step by step through creating a Google OAuth "Web" client
   (you can't log into my Google account, so guide me through the Cloud Console:
   create the project, configure the consent screen, create the OAuth client,
   and tell me exactly what to click), then collect the resulting
   AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET from me.
5. Set env vars: SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY (Supabase → Settings → API),
   AUTH_SECRET (generate with `npx auth secret`), AUTHORIZED_EMAIL=<my email>,
   AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET.
6. Deploy, then tell me to register https://<domain>/api/auth/callback/google
   as a redirect URI on the Google client.
7. Return the live URL.

The agent does everything else; for the Google OAuth app it walks you through the clicks (it can't log into your Google account) and takes the client ID/secret back from you.

3️⃣  Self-host with Docker  — your own server, no Vercel

Fully self-contained — no cloud accounts. The stack bundles Postgres + PostgREST (replaces Supabase) and the local filesystem store (replaces Vercel Blob), plus a cron sidecar. Everything runs on your host; only Google sign-in reaches the internet. Data lives in ./data/postgres (text) + ./data/uploads (binaries) — back up those two folders.

git clone https://github.com/joiha-steven/vibeblog.git && cd vibeblog
cp .env.docker.example .env.docker
node scripts/docker/gen-keys.mjs >> .env.docker   # DB password + JWT secret + service key
# then fill AUTH_SECRET, AUTH_GOOGLE_ID/SECRET, AUTHORIZED_EMAIL, SITE_URL, CRON_SECRET
docker compose up -d --build   # app on :3000 + db + rest + cron

Then point a reverse proxy / TLS at port 3000, and register <SITE_URL>/api/auth/callback/google (and <SITE_URL>/api/backup/callback for Drive backups) on your Google OAuth client. The image needs no backend env to build — secrets are supplied at runtime. The bundled DB applies scripts/schema.sql automatically on first boot. Prefer a managed database? Point SUPABASE_URL at any Supabase project and drop the db/rest services — see .env.docker.example. The Vercel path is unchanged (Supabase + Blob).

Tip

Vercel: two vercel.json knobs to make yours — regions (defaults to sin1/Singapore — set your nearest) and maxDuration: 60 for uploads (the free Hobby plan caps function time, so trim it or upgrade to Pro for big photos). Docker: large uploads have no 4.5 MB cap (the browser posts straight to the server), so big photos just work.


🤖 Let an AI agent write & publish (MCP)

vibeblog ships a remote MCP server, so a second AI agent can run your blog — drafting, editing, tagging, and publishing straight to the live site. No git, no deploy: content goes into Supabase + Blob through the same data layer (and same slug/revision/soft-delete rules) the admin uses.

  1. Turn it onAdmin → Settings → Advanced → MCP, generate a named token (shown once, hashed at rest, expires in 180 days).
  2. Connect your agent to the endpoint https://<your-domain>/api/mcp with Authorization: Bearer <token> (OAuth connectors are supported too).
  3. Prompt it, e.g.:
Using the vibeblog MCP server, write a 600-word post titled
"What I learned shipping a blog with an AI agent", give it the tags
"ai" and "writing", set a friendly excerpt, and publish it.

The post is live in seconds. Sensitive settings are blocked over MCP, and you stay the sole authority — revoke any token from the admin and it's gone.


🔑 Environment variables

See .env.example. The essentials:

Variable Required What it is · where to get it
AUTH_SECRET NextAuth secret — generate with npx auth secret
AUTHORIZED_EMAIL The only email allowed into /admin — your email
AUTH_GOOGLE_ID / AUTH_GOOGLE_SECRET Google OAuth "Web" client (admin sign-in + optional commenter login) — Cloud Console → Credentials
SUPABASE_URL Supabase project API URL — Supabase → Settings → API. Docker: auto-set to the bundled PostgREST (http://rest:3000)
SUPABASE_SERVICE_ROLE_KEY Supabase service_role key (secret, server-only) — same page. Docker: generate with node scripts/docker/gen-keys.mjs
POSTGRES_PASSWORD / SUPABASE_JWT_SECRET ◻️ Docker Bundled-DB secrets for the local Postgres + PostgREST — produced by gen-keys.mjs alongside the key above
BLOB_READ_WRITE_TOKEN ✅ Vercel Vercel Blob token — auto-injected when you connect a Blob store; also derives the public Blob URL. Not used on Docker (local filesystem driver)
STORAGE_DRIVER ◻️ Docker vercel-blob (default) or local. The Docker image bakes in local; binaries go to STORAGE_LOCAL_DIR (default /app/uploads)
SITE_URL ◻️ Docker Canonical public URL of the instance (Vercel infers this automatically). Used for OG/sitemap/auth callbacks when self-hosting
CRON_SECRET ◻️ optional Protects /api/cron (keep-alive + scheduled backup) — any random string. On Docker the cron sidecar sends it
MCP_OAUTH_SECRET ◻️ optional Signs MCP OAuth codes — random; falls back to AUTH_SECRET
Turnstile / Facebook keys ◻️ optional Comment anti-spam (Cloudflare Turnstile) + Facebook commenter login — enter these in Admin → Settings (stored server-side). The matching env vars (TURNSTILE_*, AUTH_FACEBOOK_*) still work as a fallback

MCP tokens and the Google Drive backup connection are created in the admin, not via env. Secrets stay in .env.local (gitignored) + Vercel (vercel env pull) — or .env.docker when self-hosting; your blog content lives in Supabase + Blob (or the bundled Postgres + local volume on Docker), never in git. The full self-host set is in .env.docker.example.


🧑‍💻 Run locally (optional)

git clone https://github.com/joiha-steven/vibeblog.git && cd vibeblog
npm install
cp .env.example .env.local        # fill in the values above
npx auth secret                   # AUTH_SECRET
npm run dev                       # http://localhost:3000/admin

Point the same Supabase + Blob at local, and add http://localhost:3000/api/auth/callback/google to your Google client. npm run check:all must pass before any change is done (typecheck + lint + invariant checks + the vitest seam tests; offline, no creds); npm run build for a release.


⚙️ Using it

  • / — public blog (published, date-reached posts) · /category/<slug>, /tag/<slug> (slugified) · header search overlay · path-based pagination (/page/2).
  • /admin — dashboard, editor, media, analytics, settings (owner only).
  • Settings is one form / one Save, three tabs — General (site, menu, reader features, SEO), Appearance (palettes, custom font, the per-role text-size table), Advanced (MCP, backups, custom CSS). Everything is injected as CSS variables, so changes apply site-wide with no redeploy.
  • Performance: public pages are ISR-cached; every admin save purges exactly the affected pages through one place (src/lib/revalidate.ts), so edits are live next request without ever serving stale. Full design + the why in ARCHITECTURE.md.

🗺️ Roadmap

Docker self-host shipped (local filesystem storage); next up: an S3/MinIO storage driver + a published GHCR image, publishing from Markdown note apps (Obsidian → Craft), and optional AI assist in the editor. See ROADMAP.md.


📄 License

Two separate layers — keep them distinct:

  • Code (this repo) — MIT. Free and open source: use, modify, redistribute, or sell it for any purpose, no obligation to credit (MIT only asks the license text travels with copies of the source). Fork it and run your own blog.
  • Content — © all rights reserved. The writing published with vibeblog (articles, images on an operator's site, e.g. manhhung.me) belongs to its author, is not covered by MIT, does not live in this repo, and may not be reused without permission.

In short: the software is open for anyone; the author's writing is not.

About

Open-source, AI-operated personal blog — write in a polished multilingual admin or hand the keys to an AI agent over MCP. Fast, readable, fully tweakable. Next.js 16 + Supabase, on Vercel or self-hosted with Docker.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors