内容
<div align="center">
# 博客平台 `v1.1.8`
**一个由 AI 驱动的个人博客平台。**
从简洁的多语言后台撰写和发布文章,或者将控制权交给 AI 代理,让它为您撰写、发布,甚至部署。
<br/>









[**🌐 在线演示**](https://manhhung.me) · [**获取自己的副本**](#-获取自己的副本) · [**让 AI 代理运行它**](#-让-ai-代理撰写--发布-mcp) · [**架构**](./ARCHITECTURE.md) · [**路线图**](./ROADMAP.md) · [**许可证**](#-许可证)
<sub>在 **manhhung.me** 上的演示是作者的个人博客 — 一个实时实例,展示该平台的运行效果,而非内容展示(忽略内容,关注其工作原理)。</sub>
<br/>
<img src="docs/demo.jpg" alt="vibeblog 管理后台和阅读视图" width="900">
</div>
---
## ✨ 什么是 vibeblog
一个 **开源** (MIT)的单用户博客,适用于那些只想 **写作** 的人。公共站点使用静态缓存,因此在 **移动设备和桌面设备上加载速度极快**,并且针对 **易读的排版** 进行优化 — 干净的阅读体验第一。所有内容都 **易于在后台调整** (调色板、字体、菜单、字体),**没有任何硬编码值**,因此您可以自定义它而无需修改代码。
所有写作都在精致的 `/admin` (或通过 MCP)进行。文本存储在 **Postgres** (Supabase on Vercel 或自托管时的捆绑 Postgres);二进制文件(图像、文件、图标)通过可插拔的存储驱动程序 — **默认为 Vercel Blob**,或 Docker 上的 **本地文件系统**。无需 git push 发布,无需 CMS 维护。
| 区域 | 您获得的内容 |
|:---|:---|
| 🖋️ **编辑器** | TipTap 3 + Markdown · 响应式 `sharp` 图像(原始 + AVIF/WebP 变体)· 3 版本时间机 · 60 秒自动保存 |
| 🎨 **外观** | 6 个可自定义的浅色 + 深色调色板 · 一个可调的字体系统(每个角色的尺寸/行高/跟踪,无硬编码尺寸) · 上传每个字重的自定义字体 |
| 🌍 **国际化** | 后台 + 站点支持 `en · vi · de · ja · zh · ko` |
| 🔍 **阅读** | 即时本地 + Postgres 全文搜索 · 目录 · 相关帖子 · 阅读时间 · 进度条 |
| 📈 **内置** | 无 cookie 分析(浏览量/访客/热门页面,无 PII)· 活动日志 · 软删除回收站(不会自动清除) |
| 🔎 **SEO** | 站点地图 · RSS · `robots.txt` · `llms.txt` · 动态 OG 图像 — 所有可切换 |
| 💾 **备份** | 一键式完整快照(DB + 所有二进制文件)到 **Google Drive**,可调度 + 恢复 |
| 🤖 **MCP** | 一个远程端点,允许 AI 代理使用与后台相同的规则撰写和管理博客 |
| 📱 **PWA** | 可安装,独立启动 |
| 🔐 **身份验证** | NextAuth v5 · Google 登录 · 单个授权所有者 · 边缘保护的后台/API |
| 🚀 **部署** | Vercel + Supabase (+ Vercel Blob),或使用 **Docker** 自托管 — 捆绑 Postgres + 本地存储,**无需云服务** — 相同的代码库 |
> 构建于 **Next.js 16** (App Router,React 19,严格的 TS)+ **Tailwind v4**,部署在 **Vercel** 或使用 **Docker** 自托管。
**适用人群** — 想要一个快速、好看、完全自主的博客,由一个人拥有,在 Vercel + Supabase 上运行 **或使用 Docker 自托管**,并且喜欢让 AI 代理帮助运行博客的想法。
**不适用于** — 需要角色和编辑工作流的多作者团队/出版物。vibeblog 设计为单用户;多租户功能在计划中的 SaaS 中提供,不在此处提供。
---
## 🚀 获取自己的副本
三种方式可以建立自己的博客 — **请选择一种**。每种方式最终都会在您的域名上运行一个实时网站。
<details>
<summary><b>1️⃣ 自行搭建</b> — 约 10 分钟完成</summary>
<br/>
1. **Fork** 此仓库(以便 Vercel 部署您的副本)。
2. **数据库** — 创建一个 [Supabase](https://supabase.com) 项目 → SQL 编辑器 → 粘贴 [`scripts/schema.sql`](./scripts/schema.sql) → **运行**(幂等)。复制 **项目网址** + **`service_role`** 密钥(设置 → API)。
3. **导入到 Vercel** — *添加新项目 → 项目* → 导入您的 fork。
4. **Blob 存储** — *存储 → 创建 → Blob*,连接到项目。这会自动注入 `BLOB_READ_WRITE_TOKEN`。
5. **环境变量** (设置 → 环境变量 — 见 [表格](#-环境变量)):
`SUPABASE_URL`、`SUPABASE_SERVICE_ROLE_KEY`、`AUTH_SECRET`(`npx auth secret`)、`AUTHORIZED_EMAIL`、`AUTH_GOOGLE_ID`、`AUTH_GOOGLE_SECRET`。
6. **部署**。然后在您的 [Google OAuth 客户端](https://console.cloud.google.com/apis/credentials) 中添加重定向 URI `https://<您的域名>/api/auth/callback/google`。
7. 打开 `https://<您的域名>/admin`,以 `AUTHORIZED_EMAIL` 身份登录,在 **设置** 中设置您的标题/调色板/菜单,然后开始写作。
</details>
<details>
<summary><b>2️⃣ 交给 AI 代理</b> — Claude、OpenAI Codex、OpenClaw、Hermes...</summary>
<br/>
给予代理 **Vercel + Supabase + GitHub 访问权限** (令牌/CLI/MCP),然后粘贴:
```text
部署我自己的 vibeblog 副本:
1. 将仓库 fork 到我的账户。
2. 创建一个 Supabase 项目,并在其 SQL 编辑器中运行 scripts/schema.sql。
3. 从 fork 创建一个 Vercel 项目;添加一个 Vercel Blob 存储(这会设置 BLOB_READ_WRITE_TOKEN)。
4. 带我逐步完成创建 Google OAuth "Web" 客户端的过程
(您无法登录我的 Google 账户,因此请指导我完成 Cloud Console
的操作:创建项目,配置同意屏幕,创建 OAuth 客户端,
并告诉我需要点击的确切位置),然后收集生成的
AUTH_GOOGLE_ID 和 AUTH_GOOGLE_SECRET。
5. 设置环境变量:SUPABASE_URL、SUPABASE_SERVICE_ROLE_KEY(Supabase → 设置 → API)、
AUTH_SECRET(使用 `npx auth secret` 生成)、AUTHORIZED_EMAIL=<我的电子邮件>、
AUTH_GOOGLE_ID 和 AUTH_GOOGLE_SECRET。
6. 部署,然后告诉我将 https://<域名>/api/auth/callback/google
注册为 Google 客户端上的重定向 URI。
7. 返回实时网址。
```
> 代理执行其他所有操作;对于 Google OAuth 应用,它 **引导您完成点击操作** (它无法登录您的 Google 账户),并从您那里获取客户端 ID/密钥。
</details>
<details>
<summary><b>3️⃣ 使用 Docker 自托管</b> — 您自己的服务器,无需 Vercel</summary>
<br/>
**完全自包含 — 无需云服务账户**。堆栈捆绑 **Postgres + PostgREST** (替换 Supabase)和 **本地文件系统** 存储(替换 Vercel Blob),以及一个 cron 侧车。所有内容都在您的主机上运行;只有 Google 登录需要访问互联网。数据存储在 `./data/postgres` (文本)+ `./data/uploads` (二进制文件)中 — 备份这两个文件夹。
```bash
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 # 数据库密码 + JWT 密钥 + 服务密钥
# 然后填写 AUTH_SECRET、AUTH_GOOGLE_ID/SECRET、AUTHORIZED_EMAIL、SITE_URL、CRON_SECRET
docker compose up -d --build # 应用程序在 :3000 + 数据库 + rest + cron
```
然后将反向代理/TLS 指向端口 `3000`,并在您的 Google OAuth 客户端上注册 `<SITE_URL>/api/auth/callback/google`(以及 `<SITE_URL>/api/backup/callback` 以进行 Drive 备份)。镜像 **不需要后端环境变量来构建** — 运行时提供密钥。捆绑的数据库在首次启动时自动应用 `scripts/schema.sql`。如果您更喜欢托管数据库,请将 `SUPABASE_URL` 指向任意 Supabase 项目,并删除 `db`/`rest` 服务 — 参见 [`.env.docker.example`](./.env.docker.example)。Vercel 路径保持不变(Supabase + Blob)。
</details>
> [!TIP]
> **Vercel:** 两个 `vercel.json` 旋钮可使您的项目生效 — `regions`(默认为 `sin1`/新加坡 — 设置您最近的)和 `maxDuration: 60` 用于上传(免费 Hobby 计划限制函数时间,因此修剪它或升级到 Pro 以处理大照片)。**Docker:** 大型上传没有 4.5 MB 的限制(浏览器直接发布到服务器),因此大照片直接生效。
---
## 🤖 让 AI 代理撰写和发布(MCP)
vibeblog 配备了一个远程 **MCP** 服务器,因此第二个 AI 代理可以运行您的博客 — 起草、编辑、标记和 **直接发布到实时站点**。无需 git,无需部署:内容通过与后台使用的相同数据层(以及相同的 slug/revision/软删除规则)进入 Supabase + Blob。
1. **启用它** — *后台 → 设置 → 高级 → MCP*,生成一个命名令牌(显示 **一次**,静止时哈希,180 天后过期)。
2. **连接您的代理** 到端点 `https://<您的域名>/api/mcp`,使用 `Authorization: Bearer <令牌>`(也支持 OAuth 连接器)。
3. **提示它**,例如:
```text
使用 vibeblog MCP 服务器,撰写一篇 600 字的帖子,标题为
“What I learned shipping a blog with an AI agent”,赋予它标签
“ai”和“writing”,设置一个友好的摘录,然后发布。
```
帖子会在几秒钟内上线。MCP 上会阻止敏感设置,您仍然是唯一的管理者 — 在后台撤销任何令牌,它就会消失。
---
## 🔑 环境变量
参见 [`.env.example`](./.env.example)。基本变量:
| 变量 | 必需 | 它是什么 · 在哪里获取 |
|---|:---:|---|
| `AUTH_SECRET` | ✅ | NextAuth 密钥 — 使用 `npx auth secret` 生成 |
| `AUTHORIZED_EMAIL` | ✅ | 唯一允许进入 `/admin` 的电子邮件 — 您的电子邮件 |
| `AUTH_GOOGLE_ID` / `AUTH_GOOGLE_SECRET` | ✅ | Google OAuth "Web" 客户端(后台登录 + 可选的评论者登录) — [Cloud Console → Credentials](https://console.cloud.google.com/apis/credentials) |
| `SUPABASE_URL` | ✅ | Supabase 项目 API URL — Supabase → 设置 → API。 **Docker:** 自动设置为捆绑的 PostgREST (`http://rest:3000`) |
| `SUPABASE_SERVICE_ROLE_KEY` | ✅ | Supabase `service_role` 密钥(秘密,仅限服务器) — 相同的页面。 **Docker:** 使用 `node scripts/docker/gen-keys.mjs` 生成 |
| `POSTGRES_PASSWORD` / `SUPABASE_JWT_SECRET` | ◻️ Docker | 捆绑数据库的秘密 — 由 `gen-keys.mjs` 与上面的密钥一起生成 |
| `BLOB_READ_WRITE_TOKEN` | ✅ Vercel | Vercel Blob 令牌 — **自动注入** 连接 Blob 存储时;还派生公共 Blob URL。 **Docker 上不使用** (本地文件系统驱动程序) |
| `STORAGE_DRIVER` | ◻️ Docker | `vercel-blob`(默认)或 `local`。Docker 镜像内置 `local`;二进制文件进入 `STORAGE_LOCAL_DIR`(默认为 `/app/uploads`) |
| `SITE_URL` | ◻️ Docker | 实例的规范公共 URL(Vercel 自动推断)。用于 OG/站点地图/身份验证回调,自托管时 |
| `CRON_SECRET` | ◻️ 可选 | 保护 `/api/cron`(保持活动 + 调度备份) — 任意字符串。在 Docker 上,cron 侧车发送它 |
| `MCP_OAUTH_SECRET` | ◻️ 可选 | 签名 MCP OAuth 代码 — 随机;默认为 `AUTH_SECRET` |
| Turnstile / Facebook 密钥 | ◻️ 可选 | 评论反垃圾邮件(Cloudflare Turnstile)+ Facebook 评论者登录 — **在后台 → 设置** 输入这些(服务器端存储)。匹配的环境变量(`TURNSTILE_*`,`AUTH_FACEBOOK_*`)仍然作为后备 |
MCP 令牌和 Google Drive 备份连接在 **后台创建**,而非通过环境变量。秘密存储在 `.env.local`(gitignored)+ Vercel(`vercel env pull`)— 或自托管时的 `.env.docker`; 您的博客内容存储在 Supabase + Blob(或 Docker 上的捆绑 Postgres + 本地卷),永远不会进入 git。完整的自托管设置在 [`.env.docker.example`](./.env.docker.example) 中。
---
## 🧑💻 本地运行(可选)
```bash
git clone https://github.com/joiha-steven/vibeblog.git && cd vibeblog
npm install
cp .env.example .env.local # 填写上面的值
npx auth secret # AUTH_SECRET
npm run dev # http://localhost:3000/admin
```
将相同的 Supabase + Blob 指向本地,并将 `http://localhost:3000/api/auth/callback/google` 添加到您的 Google 客户端。`npm run check:all` 必须通过任何更改(类型检查 + lint + 不变性检查 + vitest 缝隙测试;离线,无凭证);`npm run build` 用于发布。
---
## ⚙️ 使用它
- `/` — 公共博客(已发布,按日期到达的帖子)· `/category/<slug>`,`/tag/<slug>`(slugfied)· 头部搜索叠加层 · 基于路径的分页(`/page/2`)。
- `/admin` — 仪表板、编辑器、媒体、分析、设置(仅限所有者)。
- **设置** 是一个表单 / 一个保存,三个选项卡 — **常规**(站点、菜单、读者功能、SEO)、**外观**(调色板、自定义字体、每个角色的文本大小表)、**高级**(MCP、备份、自定义 CSS)。所有内容都注入为 CSS 变量,因此更改会立即在整个站点生效,而无需 **重新部署**。
- **性能:** 公共页面使用 ISR 缓存;每次管理员保存都会清除受影响的页面([`src/lib/revalidate.ts`](./src/lib/revalidate.ts)),因此编辑会在下一个请求时生效,而不会提供过时内容。完整的设计 + 说明见 [`ARCHITECTURE.md`](./ARCHITECTURE.md)。
---
## 🗺️ 路线图
Docker 自托管已发货(本地文件系统存储);接下来是 S3/MinIO 存储驱动程序和发布的 GHCR 镜像,从 Markdown 笔记应用(Obsidian → Craft)和编辑器中的可选 AI 协助。见 [`ROADMAP.md`](./ROADMAP.md)。
---
## 📄 许可证
两个独立的层 — 保持它们不同:
- **代码(此仓库)— [MIT](./LICENSE).** 免费且开源:使用、修改、重新分发或将其用于任何目的,**无需义务提及**(MIT 仅要求许可证文本随副本)。 fork 它并运行自己的博客。
- **内容 — © 保留所有权利.** 使用 vibeblog **发布的内容**(文章、图像、操作员站点上的图像,例如 manhhung.me)属于其作者,**不** 受 MIT 保护,不包含在此仓库中,且未经许可不得重用。
> 简而言之:**软件** 对任何人开放;**作者的写作** 不是。
连接信息
猜你喜欢
暂无推荐服务器