途中书写在技术与生活的路上,持续记录
← 返回文章

所感 · 2026-09-26

doocs,GitHub同步及Cloudflare图床

前段时间介绍过一款开源的公众号排版工具doocs,后来将其部署在服务器上,用了一段时间,总体还是很方便的。

Doocs更新:GitHub同步及Cloudflare图床

前段时间介绍过一款开源的公众号排版工具doocs,后来将其部署在服务器上,用了一段时间,总体还是很方便的。

不过使用中也发现两个问题:文章默认保存在浏览器本地,换电脑或者清理浏览器数据后不方便继续编辑;另外,文章中的图片也需要找一个稳定的图床。

新版的系统已经支持同步,但官方的GitHub 同步功能依赖 Doocs 官方账户 API,且OAuth 回调域名与自建域名不匹配。

故最近把这两个问题处理了一下:

  • 使用GitHub登录,实现文章及常用设置的云端同步
  • 使用Cloudflare R2作为图床,免费额度基本够个人公众号使用

本文算是上一篇文章的更新,主要记录配置方法及几个容易踩坑的地方。

上一篇文章:doocs,公众号开源排版工具

项目地址:https://github.com/doocs/md

官方演示地址:https://md.doocs.org/

<!-- 建议插图:登录后的 doocs 首页,能看到同步状态及 Cloudflare R2 选项 -->

GitHub同步

新版doocs支持使用GitHub账号登录。登录后,可以在不同电脑及浏览器之间同步文章和部分编辑器设置。

需要注意的是,所谓GitHub同步,并不是把每篇文章保存为Markdown文件后提交到GitHub仓库。

GitHub在这里主要承担账号登录及身份认证的作用,文章正文实际保存在部署方配置的Cloudflare D1数据库中。

简单来说,整个过程大致如下:

浏览器
  ↓ GitHub登录
Cloudflare Worker
  ↓
Cloudflare D1数据库

<!-- 建议插图:GitHub登录按钮及授权页面 -->

登录成功后,打开云同步功能,点击“立即同步”,当前浏览器中的文章会上传至云端;在另一台电脑登录同一个GitHub账号,再执行同步,就可以继续编辑。

免费版本支持手动同步,目前默认限制为每小时30次,对个人写作来说已经足够。Pro版本支持编辑后自动同步,同时提高同步频率。

私有部署配置

如果只是使用官方站点,不需要自己配置GitHub OAuth。若使用Docker或自己的域名私有部署,则需要同时部署官方提供的后端API,并在GitHub创建OAuth App。

在GitHub中依次进入:

Settings
→ Developer settings
→ OAuth Apps
→ New OAuth App

主要填写以下内容:

Application name:自定义,例如 doocs-md
Homepage URL:https://你的doocs域名
Authorization callback URL:https://你的API域名/auth/github/callback

回调地址必须与实际地址完全一致,包括https、域名和路径,否则登录后可能跳回官方站点、出现空白页面,或者直接提示回调地址错误。

创建后会得到Client ID和Client Secret,在后端设置:

pnpm api exec wrangler secret put GITHUB_CLIENT_ID
pnpm api exec wrangler secret put GITHUB_CLIENT_SECRET
pnpm api exec wrangler secret put JWT_SECRET

其中JWT_SECRET应使用随机生成的高强度字符串,例如:

openssl rand -hex 32

前端还需要指定自己的API地址:

VITE_SYNC_API_URL=https://你的API域名

部分版本中变量名称可能显示为VITE_MD_API_URL,应以当前项目中的.env.example及实际源码为准,不要同时凭感觉填写多个地址。

同步到底保存了什么

根据当前版本,云同步主要包含:

  • 文章正文
  • 文章历史记录
  • 删除状态
  • 同步白名单内的编辑器偏好设置

以下内容不会同步:

  • GitHub Token
  • Cloudflare R2 Access Key
  • AI平台密钥
  • 其他图床账号及密码

这是合理的安全设计,但也意味着换电脑后,文章可以同步回来,图床配置仍需重新填写。

另外,云同步不能完全代替备份。重新部署前,特别是准备删除Worker、D1数据库或更换Cloudflare账号时,仍建议手工导出文章和配置。

GitHub负责登录,D1负责保存文章,R2负责保存图片,三者并不是同一件事。

Cloudflare R2图床

doocs支持GitHub、阿里云OSS、腾讯云、七牛云、S3、MinIO及Cloudflare R2等多种图床。

之前测试过阿里云OSS,上传本身没有问题,但如果图片通过OSS公网地址被大量访问,会产生存储、请求及公网流量费用。

Cloudflare R2的优势是公网出口流量免费,并且每月包含一定的免费额度:

  • 10GB标准存储
  • 100万次A类操作,主要是上传及修改
  • 1000万次B类操作,主要是读取
  • 公网出口流量免费

对于普通个人公众号来说,一般很难超过免费额度。需要注意,R2仍属于按量计费服务,开通时需要绑定支付方式,超过免费额度后会产生费用。

官方价格说明:https://developers.cloudflare.com/r2/pricing/

创建Bucket

进入Cloudflare控制台,打开:

存储和数据库
→ R2对象存储
→ 创建存储桶

例如:

Bucket名称:doocs-images
位置:自动
默认存储类:标准

一定要选择“标准”存储类,R2免费额度目前只适用于标准存储。

<!-- 建议插图:R2 Bucket创建页面 -->

绑定自定义域名

不建议正式使用r2.dev开发地址,该地址主要用于测试,存在访问频率限制,并且不能正常使用Cloudflare缓存、WAF等能力。

在Bucket设置中绑定自己的子域名,例如:

https://img.example.com

绑定后,Cloudflare会自动增加对应DNS记录。域名初次连接可能需要等待几分钟,状态显示“活动”后再测试。

<!-- 建议插图:R2自定义域名已启用 -->

配置CORS

这是最容易漏掉的一步。

图片是由浏览器直接上传到R2的,如果没有配置CORS,保存参数可能正常,但真正上传时会提示:

Failed to fetch

进入Bucket的“设置”页面,在CORS策略中加入以下内容:

[
  {
    "AllowedOrigins": [
      "https://你的doocs域名"
    ],
    "AllowedMethods": [
      "GET",
      "HEAD",
      "PUT"
    ],
    "AllowedHeaders": [
      "*"
    ],
    "ExposeHeaders": [
      "ETag"
    ],
    "MaxAgeSeconds": 3600
  }
]

AllowedOrigins不要直接照抄示例,需要改为实际使用的doocs域名,而且要包含https://,结尾不要随意增加路径。

如果同时在本地调试,可以加入第二个来源:

"AllowedOrigins": [
  "https://你的doocs域名",
  "http://localhost:8080"
]

不建议为了省事直接配置为*。虽然CORS本身不是身份认证,但限制来源仍可以减少密钥被误用后的风险。

创建最小权限密钥

在R2的“管理API令牌”中创建一个专用令牌,建议配置为:

令牌名称:doocs-images-uploader
权限:对象读和写
作用范围:仅指定 doocs-images Bucket
有效期:按实际需要选择

不要选择整个账户的管理员读写权限,也不要把日常使用的Cloudflare全局API Token填进doocs。

创建完成后会得到:

Account ID
Access Key ID
Secret Access Key

Secret Access Key只会显示一次,应立即保存在密码管理器中。文章、截图、GitHub仓库及聊天记录中都不应出现真实密钥。

doocs中填写

打开“本地上传”,选择Cloudflare R2,填写:

AccountId:<你的Cloudflare Account ID>
AccessKey:<R2 Access Key ID>
SecretKey:<R2 Secret Access Key>
Bucket:doocs-images
域名:https://img.example.com
存储路径:weixin

保存后,再回到“选择上传”页面,把默认图床切换为Cloudflare R2。

<!-- 建议插图:doocs的Cloudflare R2配置页面 -->

先上传一张小图片测试,成功后Markdown中应出现类似地址:

图片地址示例:`https://img.example.com/weixin/文件名.png`

如果能上传但不能预览,优先检查以下几项:

  1. 自定义域名是否已经变为“活动”状态
  2. 域名是否填写了完整的https://
  3. Bucket是否已通过自定义域名公开读取
  4. CORS中的来源域名是否正确
  5. Access Key是否具有目标Bucket的对象读写权限

粘贴到公众号后,图片还走R2吗

通常把排版结果复制到公众号后台后,微信会抓取外部图片并转存到自己的图片服务器,最终文章中的地址一般会变成:

https://mmbiz.qlogo.cn/...

正式发布后,读者主要访问的是微信图片CDN,而不是直接访问R2地址。

不过在doocs编辑、预览及粘贴转存过程中,原始R2图片必须保持公开可读。如果图片设置为私有、域名失效或防盗链规则过严,微信后台就可能抓取失败。

发布前可以保存公众号草稿,再检查图片地址是否已经变为mmbiz.qlogo.cn。

升级及备份

如果使用Docker部署,升级前建议先记录当前镜像版本及环境变量,并备份D1数据库。

仅更新前端容器的一般操作如下:

docker pull doocs/md:latest
docker stop doocs
docker rm doocs
docker run -d \
  --name doocs \
  --restart unless-stopped \
  -p 8080:80 \
  doocs/md:latest

如果还自行部署了同步API,则不能只保留前端容器。GitHub OAuth配置、Worker Secrets、D1数据库绑定、自定义域名等都应单独记录。

至少建议保留三类备份:

  • doocs手工导出的文章及配置
  • Cloudflare D1数据库备份
  • Worker、环境变量及域名配置说明

R2中的图片独立保存在Bucket中,重建前端容器不会删除图片;但如果删除Bucket或Cloudflare账号,图片链接会直接失效。

建议及优化

从实际使用情况来看,加入云同步和R2图床以后,doocs才算真正适合长期使用。

GitHub登录解决了换电脑继续编辑的问题,Cloudflare R2则解决了图片存储及流量费用的问题,两者配合起来比较省心。

当然,目前仍有几个需要注意的地方:

  • 云同步不是GitHub仓库备份,文章实际保存在D1
  • 图床密钥不会跟随文章同步,换电脑后需要重新配置
  • R2免费但不是无限免费,建议开启预算提醒
  • 不要在公开文章、源码或截图中泄露任何Secret
  • 私有部署升级前,应先备份D1及手工导出文章

另外,如果doocs放在公网上,仍建议限制访问范围,或者加入Cloudflare Access、反向代理认证等措施,避免任何人都能直接使用自己的服务及图床额度。

写在途中,持续记录。继续阅读 →