一键部署在 Cloudflare 上的私人加密笔记系统 完全免费

304次阅读
没有评论

https://github.com/tao-t356/private-notes

第一部分:为什么要做这个项目

现在市面上的笔记软件其实非常多。

比如 Notion、飞书、语雀、Obsidian、Apple Notes、Google Keep 等等。
这些工具都很好,但它们往往有几个问题。

第一个问题是,数据不完全在自己手里

很多在线笔记工具,数据都存在平台服务器上。
当然大平台一般也很安全,但是对于一些非常私人的内容,比如:

  • 日记
  • 想法
  • 密码提示
  • 私人计划
  • 临时灵感
  • 账号记录
  • 读书笔记
  • 工作草稿

有些人就是不想放到第三方平台里。

第二个问题是,功能太重

很多笔记软件越来越复杂。
一打开就是数据库、模板、团队空间、协作、AI、看板、表格、日历……

但有时候我们只是想要一个很简单的东西:

打开,输入,保存,搜索,结束。

第三个问题是,手机端体验不一定轻量

有些软件 App 很大,有些网页版在手机上不太舒服。
而我想要的是一个手机浏览器能打开,也可以添加到主屏幕的小应用。

第四个问题是,自己部署的门槛太高

很多开源笔记项目需要:

  • 自己买 VPS
  • 安装 Docker
  • 配置数据库
  • 配置反向代理
  • 配置 HTTPS
  • 维护服务

对普通用户来说太麻烦了。

所以这个项目的目标就是:

用尽可能轻的方式,做一个可以部署在 Cloudflare 上的私人加密笔记。


第二部分:这个项目是什么

这个项目叫 Private Notes

它的核心架构很简单:

浏览器 ↓ Cloudflare Workers ↓ Cloudflare D1

前端页面直接由 Worker 返回。
后端 API 也在同一个 Worker 里。
数据存储用的是 Cloudflare D1。

它没有复杂的前后端分离,也没有额外服务器。
只要 Cloudflare 能跑 Workers,就能跑这个项目。

这个项目最重要的特点是:

1. 端到端加密

笔记内容不是直接明文存进数据库的。

用户输入密码之后,浏览器会用这个密码派生出本地加密密钥。
然后笔记标题和正文会在浏览器端加密,再发送到服务器保存。

也就是说,Cloudflare D1 里保存的是密文。

服务器只负责保存和读取密文,不负责解密内容。

当然,这也带来一个重要限制:

如果你忘记了密码,旧笔记无法恢复。

所以这个密码一定要记住。


2. 多密码,多数据空间

这个项目还有一个我觉得挺有意思的功能:
它支持多密码进入不同的数据空间。

比如你配置:

APP_PASSWORD=facker668 APP_PASSWORDS=guest=guest123,work=work888

那么:

  • 输入 facker668,进入默认空间
  • 输入 guest123,进入 guest 空间
  • 输入 work888,进入 work 空间

不同空间的数据是隔离的。

这有什么用呢?

比如你可以这样用:

  • 一个密码放自己的私人笔记
  • 一个密码放工作草稿
  • 一个密码给临时访客用
  • 一个密码做演示数据

别人即使知道其中一个密码,也只能看到那个密码对应的数据空间。


3. 手机端体验优化

这个项目一开始其实手机端体验不太好。

尤其是登录和刷新页面的时候,会出现一种“页面跳来跳去”的感觉。
后来我把它改成了固定 App Shell 加锁屏 Overlay 的方式。

简单来说,现在页面刷新时不会先显示登录页再跳到应用页。
而是页面结构先稳定显示,然后上面盖一个解锁层。

这样手机端体验会自然很多。


4. 没有危险的一键清空按钮

之前项目里曾经有一个“忘记密码,清空旧笔记”的按钮。

但后来我觉得这个功能非常危险。

因为这是私人笔记,如果别人误点,或者某种情况下被触发,那数据就没了。

所以现在已经移除了:

  • 前端清空按钮
  • 后端清空接口

也就是说,网页上没有一键清空旧资料的危险入口。


第三部分:实际演示

接下来我们看一下实际效果。

这里我已经部署好了一个演示站点。

打开页面之后,可以看到一个非常简单的登录界面。

上面写着 Private Notes,然后是密码输入框。

我输入密码,比如:

facker668

然后点击进入。

进入之后就可以看到笔记列表。

页面顶部有:

  • 搜索框
  • 搜索按钮
  • 新建笔记按钮
  • 退出登录按钮

下面是所有笔记。

我们点击“新建笔记”。

这里可以输入标题,比如:

今天的想法

正文可以写:

今天测试了一下这个私人笔记系统。 它部署在 Cloudflare Workers 上, 数据存在 D1 里面, 内容会在浏览器端加密。

然后点击保存。

保存之后,笔记会出现在列表里。

这里可以看到:

  • 更新时间
  • 字数
  • 标题
  • 正文
  • 复制全文按钮
  • 编辑按钮
  • 删除按钮

如果正文很长,默认会折叠,可以点击展开全文。

现在我们再测试一下搜索。

搜索关键词,比如:

Cloudflare

它会在本地搜索标题和正文。

这里要注意,因为内容是加密的,服务端没法直接搜索明文。
所以搜索是在浏览器本地解密之后完成的。


第四部分:多密码空间演示

接下来演示一下多密码空间。

假设我有两个密码:

facker668 guest123

我先用 facker668 登录,创建一条笔记:

这是默认空间里的笔记

然后退出登录。

再用 guest123 登录。

你会发现这里看不到刚才那条笔记。
因为现在进入的是 guest 空间。

我在 guest 空间创建一条:

这是 guest 空间里的笔记

然后再退出,重新用 facker668 登录。

又只能看到默认空间的内容。

这个功能对我来说很有用。

比如我录视频的时候,可以用一个演示密码。
真实私人数据放在另外一个密码里。
这样就算录屏时不小心展示了,也不会把真实数据露出来。


第五部分:技术实现讲解

下面简单讲一下技术实现。

这个项目主要由几个部分组成:

src/ index.ts Worker 后端和 API homeHtml.ts 前端页面模板 auth.ts 登录、session、多密码、限流逻辑 migrations/ D1 数据库迁移文件 wrangler.jsonc Cloudflare Workers 配置

1. Cloudflare Workers

Cloudflare Workers 负责处理所有请求。

比如:

  • / 返回前端页面
  • /api/login 登录
  • /api/session 检查登录状态
  • /api/notes 获取和创建笔记
  • /api/notes/:id 编辑和删除笔记
  • /api/crypto-config 获取加密配置

整个项目不需要 Node.js 服务器常驻运行。
Workers 是按请求运行的。


2. Cloudflare D1

D1 是 Cloudflare 提供的 SQLite 数据库。

这个项目用 D1 存:

  • 笔记密文
  • vault 信息
  • 加密 salt
  • 登录失败限流记录

笔记表里有一个很重要的字段:

vault_id

不同密码会对应不同的 vault_id。
查询笔记时会加上这个条件:

WHERE vault_id = ?

所以不同密码空间的数据不会混在一起。


3. 前端加密

前端加密用的是浏览器的 Web Crypto API。

大致流程是:

用户输入密码 ↓ PBKDF2 派生密钥 ↓ AES-GCM 加密标题和正文 ↓ 密文发送到服务端 ↓ 存进 D1

解密的时候反过来:

从 D1 读取密文 ↓ 浏览器用本地密钥解密 ↓ 显示明文

服务端不会拿到解密后的内容。


4. 登录 Session

服务端登录这块也做了一些改进。

不是简单地把密码存在 Cookie 里。
而是使用 HttpOnly Cookie 保存签名 session。

session 里会包含:

  • 版本号
  • 签发时间
  • 过期时间
  • vaultId

然后用 COOKIE_SECRET 做 HMAC 签名。

这样前端 JavaScript 不能直接读取 session cookie,安全性会好一些。


5. 登录失败限流

项目里还加了登录失败限流。

规则是:

  • 同一客户端连续失败 5 次
  • 15 分钟窗口
  • 触发后锁定 15 分钟
  • 返回 429
  • 带 Retry-After 响应头

这可以防止别人暴力猜密码。

限流记录也存在 D1 里。


第六部分:如何部署

下面讲一下怎么部署。

项目地址在 GitHub 上:

https://github.com/tao-t356/private-notes

最简单的方式是直接点 README 里的:

Deploy to Cloudflare

Cloudflare 会帮你创建 Worker 和 D1。

部署时你需要配置几个变量:

APP_PASSWORD

默认数据空间的密码。

比如:

facker668

不过我建议你正式使用时改成自己的强密码。

APP_PASSWORDS

可选。

如果你想要多个数据空间,就配置这个。

格式是:

vault_id=password,vault_id2=password2

比如:

guest=guest123,work=work888

COOKIE_SECRET

这个是用来签名 session cookie 的。

建议设置成一个长随机字符串,比如 32 位以上。


如果你手动部署,大概步骤是:

第一步,安装依赖:

npm install

第二步,登录 Cloudflare:

npx wrangler login

第三步,创建 D1 数据库:

npx wrangler d1 create private-notes-db

然后把返回的 database_id 填进 wrangler.jsonc。

第四步,执行迁移:

npx wrangler d1 migrations apply DB --remote

第五步,设置 secrets:

npx wrangler secret put APP_PASSWORD npx wrangler secret put APP_PASSWORDS npx wrangler secret put COOKIE_SECRET

其中 APP_PASSWORDS 是可选的。

第六步,部署:

npm run deploy

部署完成后,你会得到一个 workers.dev 地址。

打开之后,就可以使用自己的私人笔记了。


第七部分:适合谁使用

这个项目适合几类人。

第一类,是想要一个轻量私人笔记的人。
不需要复杂功能,只想快速记录和搜索。

第二类,是想学习 Cloudflare Workers 和 D1 的开发者。
这个项目很适合作为入门案例,因为它包含:

  • Worker API
  • D1 数据库
  • migration
  • secrets
  • session cookie
  • 前端加密
  • PWA
  • GitHub 一键部署

第三类,是想拥有自己数据的人。
不想依赖大型笔记平台,但又不想维护服务器。

第四类,是内容创作者。
比如做教程、做演示,可以用多密码空间做演示数据,不影响真实数据。


第八部分:当前限制

当然,这个项目不是完美的。

目前它还有一些限制。

第一,不支持图片和附件上传。
之前我尝试过加图片功能,用 Cloudflare R2 保存加密图片。
但是 R2 可能涉及绑卡或者计费门槛,所以最后我把图片功能去掉了。
这个项目目前还是文本优先。

第二,如果忘记密码,旧笔记无法恢复。
这是端到端加密带来的必然结果。
安全和可恢复性之间,需要做取舍。

第三,它更适合单人使用,不适合团队协作。

第四,搜索是在本地完成的。
如果笔记非常非常多,可能需要后续优化。

第五,目前 UI 还是比较轻量的,不是完整商业产品级别。

但对于一个私人轻量笔记来说,我觉得已经够用了。


第九部分:后续可以做什么

后面如果继续优化,我觉得可以加几个方向。

第一个是导出备份。

比如一键导出加密 JSON。
这样即使 D1 出问题,也能自己保存一份。

第二个是导入备份。

配合导出功能,可以迁移数据。

第三个是改密码功能。

但这个比较麻烦,因为要把所有旧笔记解密后重新加密。

第四个是更好的移动端编辑体验。

比如编辑页面改成全屏抽屉,更像原生 App。

第五个是更好的数据管理。

比如回收站、归档、标签、置顶等等。

正文完
 0
评论(没有评论)