所感 · 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`
如果能上传但不能预览,优先检查以下几项:
- 自定义域名是否已经变为“活动”状态
- 域名是否填写了完整的
https:// - Bucket是否已通过自定义域名公开读取
- CORS中的来源域名是否正确
- 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、反向代理认证等措施,避免任何人都能直接使用自己的服务及图床额度。