这篇文章就发在它自己身上:你正在看的这个博客,从代码到部署全是我自己拼的。它不用服务器、不用数据库主机、不用备案,全部跑在 Cloudflare 的免费额度里。这篇把「为什么做、抄了谁的作业、怎么一步步搭起来、有什么功能和优点、哪里还没做到」一次讲清,照着做你也能搭一个一模一样的。

一、先说为什么不用现成的

我的要求其实很朴素:手机、平板、电脑都能写文章、改文章;图片和自己拍的视频能直接传;有个网页后台,站名、颜色、布局点一点就能改;最好不花钱、不用伺候服务器。

挨个看下来的结论:

  • WordPress / Ghost / Halo / Typecho:功能最全,但都要一台服务器(或官方付费托管),有月租、要打补丁、要操心被黑。
  • 静态博客(Hexo / Hugo / Astro):免费又快,但没有真正的后台,手机上改文件发文太折腾;传视频更是死穴,只能贴外链。
  • Notion 系博客:写起来顺手,但内容命脉押在别人的 API 上,人家限流、改版、连不上,你的站就跟着抖。
  • Git 后台(Sveltia / Decap):手机体验是静态阵营里最好的,但改布局只能改预先留好的字段,视频还是只能外链。

所以最后选了第五条路:骨架用 Cloudflare 全家桶做真动态博客(文章进数据库、文件进对象存储、后台是真后台),再把上面各家被夸得最多的细节一条条挑回来拼上。这就是仓库名里「融合版」的来历。

二、它抄了谁的作业(融合来源)

不全抄,按需取舍。逐家交代清楚:

来源仓库 / 站点取了什么没取什么
Ringithub.com/openRin/Rin · 演示站 xeu.life · 文档 docs.openrin.org骨架:Pages + Workers + D1 + R2 全家桶动态路线;编辑器自动保存;文章「仅自己可见」;自带评论;正文第一张图自动当封面它的站名/简介/头像是写在部署变量里的、改一次要重新部署——没取,改成后台表单即时改;它没证实能传本地视频——我们自己把视频直传做实并实测通过
Sveltia CMSgithub.com/sveltia/sveltia-cms · sveltiacms.app设置方式:站点设置做成表单,填一填选一选就生效,不碰代码它的本体是 Git 静态后台,视频与动态能力受限——只取思路,不用本体
Halogithub.com/halo-dev/halo · halo.run备份纪律:整站导入恢复之前,强制先把当前站自动备份一份;媒体改显示名、原名只记录服务器路线没取(要 Docker/服务器)
Typechogithub.com/typecho/typecho · typecho.org仪表盘:打开后台一眼知有事——待审评论角标、最近文章、最近回复,不做数据大屏PHP 路线没取
WordPresswordpress.org三层防丢稿:本地自动保存 → 服务端自动保存(不覆盖已发布正文)→ 历史版本可还原生态与插件系统没取(那是另一个产品,也是攻击面)
Butterfly(Hexo 主题)github.com/jerryc127/hexo-theme-butterfly阅读细节:文章目录、代码块语言标注+复制按钮+折叠、文章过期提醒、阅读模式只取细节清单,不用主题本体
Fluid(Hexo 主题)github.com/fluid-dev/hexo-theme-fluid深色模式三段式:跟随系统 / 固定浅色 / 固定深色,默认跟随系统同上
AstroPapergithub.com/satnaing/astro-paper可折叠目录:长文在手机上也能跳着读同上
Twikoogithub.com/twikoojs/twikoo评论防垃圾口径:按 IP 限频、含链接多的进待审、人工审核本体不挂(评论数据要留在自己库里)
Handsome(Typecho 主题)github.com/chenyangyezi/typecho-theme-handsome热门文章 / 随机文章 / 最新评论这类「留人」小组件的思路同上

再加上自家其他站验证过的三件套:账密登录为主(不依赖任何第三方授权)、保险箱式恢复(恢复码 + 终极重置,步骤写进维修手册,不依赖任何人)、看门狗自检(每天自动巡检、先自修再报信)。

三、架构长什么样

一句话:访客页面由边缘函数在请求时直出 HTML,文章存 D1 数据库,图片视频存 R2 存储桶,代码托管在 GitHub 并自动部署。

组件用的是什么干什么
站点与函数Cloudflare Pages + Pages Functions出页面、跑接口、渲染文章
数据库Cloudflare D1(SQLite)文章、评论、说说、设置、媒体记录、备份记录
文件存储Cloudflare R2(两个桶)媒体桶存图片视频(绑公开域名);备份桶存自动备份(不公开)
代码与部署GitHub + GitHub Actions推代码自动上线;密钥只存在仓库的加密密钥库
定时任务GitHub Actions 五个工作流推送部署、看门狗巡检、友链探活(20 分钟)、每日清理、每周双通道备份

两个关键设计:

  1. 传图传视频不经过服务器:浏览器先向站点要一个「预签名地址」,然后拿着地址把文件直传进 R2,传完回站点登记一下。文件字节不流经函数——免费版函数扛不了大文件流量,这样又快又不烧额度,200MB 的视频也传得上去。
  2. 重活不在访客打开页面时做:文章在发布时就预渲染好,浏览计数按「一篇文章一天一行」聚合,备份和统计都放在定时任务里。访客读页面这条路只做最少的事,所以快、所以省额度。

四、有什么功能

写文章

  • Markdown 编辑 + 实时预览,预览和发布用同一个渲染器,所见即所得,不会「预览好好的、发出来变样」
  • 三层防丢稿:本地自动保存 → 服务端自动保存 → 切后台/关页面强制再存;写一半断电回来能接着写
  • 文章状态机:草稿 / 定时发布 / 已发布 / 仅自己可见 / 回收站(30 天可还原)
  • 定时发布不用等任务:到点了按发布时间自动出现
  • 历史版本:发布与手动保存都留版,一键还原,还原前先存当前版,每篇留最近 20 版
  • 发布面板一处配齐:自定义短链、标签、封面、摘要、置顶、单篇关评论、文章密码
  • 模板克隆:拿旧文当模板新建;草稿预览链接:带口令发给朋友先看,可过期可撤销

发图与视频

  • 粘贴 / 拖拽 / 多选直传(原理见第三节),上限后台可调:图片 20MB / 视频 200MB / 文件 50MB
  • 媒体库:改显示名、分组(相册);删文件前先数引用,被文章用着的拦下来并告诉你是哪几篇
  • 媒体回收站:删错能还原,30 天后才真删
  • 本地视频用站点自己的播放器播(能拖进度);B 站 / YouTube 贴链接单独成行自动变官方播放器
  • 没设封面时自动取正文第一张图当封面

访客看的页面

  • 服务端直出 HTML:手机弱网、微信里打开都快,分享出去能带标题和摘要
  • 阅读体验:可折叠目录、阅读进度条、代码块复制按钮、图片灯箱、字数与预计阅读时长、过期文章提醒
  • 深色模式三段式(跟随系统 / 固定浅色 / 固定深色),默认跟随系统;主题色后台可换、即时生效
  • 首页:置顶 + 文章卡片(或紧凑列表)、最新说说、那年今日、热门 Top 5、搜索框
  • 栏目页齐全:归档时间线、标签、说说页、友链页、关于页(就是一篇特殊文章,后台当普通文章改)
  • 全文搜索:标题/摘要/正文子串匹配,中文搜词不用分词、更合直觉
  • RSS 订阅源、站点地图、相关文章与上下篇(按共同标签自动算)

评论(自带,不挂第三方)

  • 数据在自己数据库里,外挂评论服务哪天关停也不受影响
  • 先审后显:新评论进待审队列,后台一键通过 / 驳回 / 标垃圾 / 删除 / 回复,站长回复带身份标记
  • 老访客免审可配;含链接多的自动进待审;按 IP 限流三档可调;可选人机验证(默认关);内容一律净化转义

安全与账号

  • 密码只存 scrypt 哈希,还加了只存在环境变量里的「胡椒」,数据库被拖走也撞不开密码
  • 连错 5 次锁 15 分钟、再犯指数退避;错误提示恒为「账号或密码错误」
  • 会话管理:能看全部登录设备、一键全下线;改密码自动踢掉所有设备
  • 三层恢复:10 个一次性恢复码 → 巡检口令窗口 → 进 Cloudflare 对数据库跑一句 SQL 回到初始化流程(步骤全在仓库维修手册里,不依赖任何人)

设置、统计、备份

  • 站名、介绍、头像、首页标题与介绍文、主题色、布局、文章宽度、深色策略、每页篇数、回收站天数、上传上限——全在后台表单里改,保存即时生效;每个开关都写了「关掉会怎样」
  • 统计页:总阅读、近 30 天热门、逐日访问量、评论趋势、媒体用量、最近备份时间
  • 每周双通道自动备份(备份桶 + GitHub 各一份,保留 12 期);一键导出 Markdown 逃生包,随时能搬去 Hugo / Astro / WordPress——平台只是托管方,不是牢笼
  • 全自动运维:推送即部署、看门狗每日巡检、友链 20 分钟探活、每日清理、心跳保活防定时任务被停

五、一步一步搭建(约 20–30 分钟,全程浏览器点点点)

第 0 步:准备两个账号

一个 GitHub 账号(放代码)、一个 Cloudflare 账号(放站点),都免费注册。

第 1 步:把仓库拿下来

打开仓库页,点右上角 Fork → 选自己的账号 → Create fork,得到一份自己的代码副本。后面改代码、推部署都在自己这份里做。

仓库主页:代码、README 部署教程、预览图都在这一个仓库里
仓库主页:代码、README 部署教程、预览图都在这一个仓库里

第 2 步:建数据库 D1

Cloudflare 后台 → Storage & Databases → D1 SQL Database → Create,名字填 ym-blog-db。点进库 → Console 页签 → 把仓库 schema/0001_init.sql 的全部内容粘贴执行,再把 schema/0002_seed.sql 同样执行一次(初始设置与示例文章)。回到库详情页记下 Database ID,第 6 步要用。

⚠️ 一个实测坑:控制台是单行输入,粘贴时要把 SQL 里的 -- 注释行去掉,否则整段会被吞掉、提示没有语句可执行。

D1 数据库 ym-blog-db 后台实况:21 张表,文章、评论、设置全存这里
D1 数据库 ym-blog-db 后台实况:21 张表,文章、评论、设置全存这里

第 3 步:建两个存储桶 R2

左侧 R2 Object Storage(从没开过会先让绑一张银行卡开通,免费额度内不扣费)。建两个桶:ym-blog-media(媒体桶)、ym-blog-backups(备份桶,不要绑任何公开域名)。

再给媒体桶做三件事:

  1. 绑域名:媒体桶 → Settings → Custom Domains → 填你的媒体域名(如博客域名的子域名)→ 状态变 Active 才算好。
  2. 配 CORS(跨域设置):媒体桶 Settings → CORS Policy 加一条:允许来源填博客域名,方法勾 PUT 和 GET。
  3. 建 S3 凭据:R2 总览页 → Manage R2 API Tokens → 权限选对象读写、只限媒体桶 → 把 Access Key ID 与 Secret Access Key 抄下来(只显示一次),第 6 步要用;顺带记下 Account ID。

⚠️ 别图省事用桶自带的 r2.dev 域名当正式地址:官方对它限流,会随机报错。

R2 对象存储:ym-blog-media 存图片视频,ym-blog-backups 存自动备份
R2 对象存储:ym-blog-media 存图片视频,ym-blog-backups 存自动备份

第 4 步:不用手动建站点项目

部署流水线第一次运行时会自动把 Pages 项目建出来,这一步看懂即可、不用动手。仓库里的 wrangler.toml 只放占位值,不要改——真值由流水线在部署时从密钥库自动替换。

第 5 步:备齐四项要填的值

PASSWORD_PEPPER(密码胡椒,至少 32 位随机字符,记牢、以后别改,改了旧密码全部验不过)、TASK_SECRET(任务口令,自己编一串),加上第 2 步的 Database ID、第 3 步的 S3 凭据,第 6 步一起填。

第 6 步:配 11 个密钥,一次部署上线

GitHub 仓库 → Settings → Secrets and variables → Actions → New repository secret,逐个加齐 11 项(部署令牌、账号 ID、数据库 ID、媒体域名、S3 端点、S3 凭据一对、站点地址、胡椒、任务口令、初始站长用户名)。这一页只显示名字、永远看不到值,安全。

仓库的 11 个部署密钥:这一页只显示名字,永远看不到值
仓库的 11 个部署密钥:这一页只显示名字,永远看不到值

配齐后随便提交一个小改动(或在 Actions 页手动 Run 一次 deploy):流水线连做三件事——替换配置占位、把运行时密钥灌进站点、部署上线。等绿勾出现,打开站点地址就是你的博客了。

GitHub Actions 运行记录:五个工作流(部署/看门狗/友链探活/清理/备份)的运行记录,绿勾即成功
GitHub Actions 运行记录:五个工作流(部署/看门狗/友链探活/清理/备份)的运行记录,绿勾即成功

第 7 步:初始化站长(最重要)

打开 https://你的域名/admin → 设用户名 + 密码(至少 8 位)→ 页面会给 10 个恢复码,只显示一次,立刻截图或抄下来收好。账号只在这一步由你亲手设定、只存哈希,不用任何环境变量预置密码。

第 8 步:绑自己的域名

前提是域名 DNS 已托管在 Cloudflare。Workers & Pages → ym-blog → Custom domains → Set up a custom domain → 填博客域名 → 证书自动签发。生效后把密钥里的 SITE_URL 改成正式域名。

Cloudflare Pages 里的 ym-blog 项目:正式域名已绑定
Cloudflare Pages 里的 ym-blog 项目:正式域名已绑定

第 9 步:上线自查清单

  • [ ] 首页能打开、示例文章在;去后台把站名和介绍改成自己的
  • [ ] 发一篇测试文,插一张图、传一个小视频,发布后前台能看、图能点大、视频能播
  • [ ] 用没登录的浏览器留一条评论,确认先进待审队列、你通过后才出现
  • [ ] 后台点一次「立即备份」,确认能生成、能下载
  • [ ] 导出一次 Markdown 逃生包,确认能下载
  • [ ] 删掉示例文章和示例说说(先进回收站,正常)

六、优点与免费额度

  • 零月租:不用服务器、不用数据库主机;域名钱之外没有固定支出。
  • 数据全在自己账号里:文章在你的 D1、文件在你的 R2、代码在你的 GitHub,不经过任何第三方托管平台。
  • 部署完不用管:自动部署、自动备份、自动巡检、自动清理,全套工作流在仓库里,换任何人接手都有维修手册可照着做。
  • 不锁死:一键导出 Markdown 逃生包,内容是平台无关格式,想走随时能走。

免费额度(官方口径,个人小站量级绰绰有余):

资源免费额度本站的省法
D1 数据库每天读 500 万行 / 写 10 万行索引齐全;浏览计数按天聚合,一文一天一行
R2 存储10GB,下载流量免费图视频直传直读,不占函数流量
Pages 函数每天 10 万次请求页面直出、发布时预渲染,读路径只做最少的事

七、诚实的边界(没做到的也写清)

  • Passkey(指纹/面容登录):只留了入口占位,没实现;现在就是账密 + 恢复码。
  • 超大视频分片上传:没做;200MB 以内直传没问题,再大的建议贴 B 站/YouTube 外链(零存储、播放更流畅)。
  • 分享图自动生成:没做;分享出去有标题和摘要,没有自动生成的封面图。
  • 友链朋友圈抓取:只做探活(通不通),不抓对方的文章标题。
  • 免费额度的脾气:超额不是降速,是停到第二天早上 8 点;所以本站在限流和缓存上按省着用的口径设计,真火了升 5 美元付费版即可解除。
  • 接口全过 ≠ 界面没毛病:本站上线当天就被我抓到一个教训——后台设置页的开关在手机上只剩一个圆钮、看不出开还是关(轨道被漏画 + 一条样式规则误伤),接口测试全过也没发现,最后是真机看出来的。当天已修复(轨道里印上开/关字、旁边加状态胶囊),并把「界面改完必须按手机尺寸真渲染截图验」写进了维修手册。
本站后台设置页(修复后):开关轨道里印着「开/关」,旁边还有状态胶囊
本站后台设置页(修复后):开关轨道里印着「开/关」,旁边还有状态胶囊

八、地址汇总

最后:这篇教程里凡是带截图的步骤,截的都是真实的 GitHub 与 Cloudflare 页面(密钥页只露名字不露值)。你现在看的这篇文章,就是这个博客的第一篇正式文章。


「ym 系列」其他文章