Memos on EdgeOne 部署教程:零数据库,纯 Blob 存储

Memos on EdgeOne 部署教程:零数据库,纯 Blob 存储
3287 字
16 分钟
Memos on EdgeOne 部署教程:零数据库,纯 Blob 存储

Memos on EdgeOne 部署教程:零数据库,纯 Blob 存储
Memos on EdgeOne 部署教程:零数据库,纯 Blob 存储

Memos 是一个轻量的自托管笔记应用,数据全部留在自己手里。问题是,传统玩法都要先有一台服务器:装 Docker、跑 SQLite、配反向代理。

如果你手上只有腾讯云 EdgeOne 账号,这篇文章就是为你准备的。memos-on-edgeone 把 Memos 迁移到了 EdgeOne Makers:不建库、不初始化、不运维,关联 GitHub 仓库推送即部署,所有数据落在 EdgeOne Blob 里。

MoonCC233
/
memos-on-edgeone
将 Memos 笔记应用迁移到 EdgeOne Makers 全栈部署平台,所有数据(包括配置、用户、备忘录等)全部存储在 EdgeOne Blob,也可选配置 S3 兼容存储。零外部依赖,纯 Blob 存储架构。
—
—
no-license
TypeScript

项目简介#

层级技术
运行时EdgeOne Makers Cloud Functions(Node.js 22.11.0)
后端框架Hono
数据存储EdgeOne Blob(默认)/ S3 兼容存储(可选)
前端React + Vite + TailwindCSS
认证JWT(HS256)+ bcrypt

它做的事情可以概括成一句话:把这个应用需要的所有东西都变成 Blob 里的几个 key。

  • 用户、备忘录、附件、实例设置,全部存储在 Blob
  • 数据库是纯 JSON 文档,命名空间首次访问时自动创建,不需要跑迁移脚本
  • 也可以整体切换到任意 S3 兼容存储(MinIO、AWS S3、Cloudflare R2、阿里云 OSS、腾讯云 COS、七牛 Kodo、又拍 USS、华为云OBS)
  • AI 语音转写走任意 OpenAI 兼容接口,自行填 endpoint 和 API Key

数据是怎么存的#

理解这一点,你就明白它为什么能”零初始化”了。

HTTPS

静态资源

/api/* /file /u/*/rss

db/*.json、instance/settings/*、attachments/*

可选:仅新附件

浏览器

EdgeOne Pages 边缘节点

前端 SPA

React + Vite

Cloud Functions

Node.js + Hono

EdgeOne Blob

命名空间 memos

S3 兼容存储

HTTPS

静态资源

/api/* /file /u/*/rss

db/*.json、instance/settings/*、attachments/*

可选:仅新附件

浏览器

EdgeOne Pages 边缘节点

前端 SPA

React + Vite

Cloud Functions

Node.js + Hono

EdgeOne Blob

命名空间 memos

S3 兼容存储

Blob 里的 key 布局非常直白:

Key内容
db/user.json、db/memo.json、db/attachment.json …十二张表,每张表是一个 { rows: [...], nextId } 的 JSON 文档
instance/settings/GENERAL、instance/settings/STORAGE、instance/settings/AI实例设置(站点名、注册开关、存储与 AI 配置)
attachments/<uid>/<filename>附件原始文件

后端没有换掉 Memos 的 SQL,而是实现了一个覆盖实际查询范围的 SQL 子集引擎(SELECT/INSERT/UPDATE/DELETE、WHERE、ORDER BY、LIMIT/OFFSET、COUNT/SUM、ON CONFLICT 等),把每条语句翻译成对内存里的行数组做过滤与写回。数据量小的时候,这套方案的读取速度和写放大都可以接受——因为个人笔记通常也就几百上千条。

为什么不用 EdgeOne KV 存储用户和配置数据#

这是很多人看到”数据存 Blob”时会问的问题:EdgeOne 不是自带 KV 吗?答案很直接——国内版 EdgeOne 的 KV 存储需要提交申请、人工审核后才能使用,因此这个项目把用户、备忘录与配置数据统一放进了 Blob。理由不止一条:

1. KV 需要申请开通,Blob 不用#

KV 存储的开通流程是:控制台顶部导航栏 → KV Storage → Apply now,然后填写申请理由、提交申请表、等待工作人员审核。也就是说,想用 KV 的部署者要先卡在一个人工审批环节,审核结果和时长不可控。

而 Blob 是零配置的:代码里第一次 getStore("memos") 调用时,平台会自动为当前项目创建同名命名空间,后续调用直接复用。既不用申请,也不用在控制台点”创建命名空间”再”绑定变量名”。

对于一个”点几下就能用起来”的部署教程,把申请审核写进前置条件是体验最差的一环。

2. KV 当前仅在 Edge Functions 运行时可用#

官方存储对比文档里写得很清楚:KV 的运行时环境是 Edge Functions only,而 Blob 支持 Edge Functions / Cloud Functions。

memos-on-edgeone 的后端是 Node.js Cloud Functions(依赖 @edgeone/pages-blob 这个 Node.js SDK,edgeone.json 里也配置了 cloudFunctions.maxDuration 与 externalNodeModules)。即使申请到了 KV 命名空间,也无法在这个运行时里直接访问——最后还是要绕回 Blob。

3. 一致性模型:用户和配置需要读后立即一致#

能力KV 存储Blob 存储
一致性最终一致性,60s 内全球同步默认最终一致,单次读可切换强一致
运行时仅 Edge FunctionsEdge Functions / Cloud Functions
启用方式控制台创建命名空间 → 绑定项目getStore('name') 直接可用
免费版存储空间1 GB1 GB
单值大小25 MB25 MB

KV 只有最终一致性,没有”读最新值”的选项。用户表、实例设置这类权威数据必须读到刚写入的内容——比如注册后立刻登录、刚改完设置就刷新页面——不能容忍最长 60 秒的延迟。

Blob 则可以在每次读取时指定 { consistency: "strong" } 绕过边缘缓存直读主存储。本项目正是这么做的:所有对 JSON 表的读取都强制强一致(worker/src/storage/index.ts 中的 EdgeOneBlobProvider 每次 get 都带 consistency: 'strong'),保证读后写成立。

Note

容量并不是原因——两者免费版都是 1 GB、单值 25 MB。真正的差别是开通门槛、运行时可用性和一致性语义。

顺带一提:以后想换回 KV 也不难#

Blob 里是纯粹的 key → JSON 文档,db/user.json 这类 key 天然可以一对一映射成 KV 的 key。也就是说,如果哪天 KV 申请下来了,把 worker/src/db/blob-database.ts 里的存储实现换成 KV 后端即可,业务层 SQL 和表结构都不用动。这也是这个项目坚持把存储收敛到一层抽象接口的原因。

部署方式一:控制台关联 Git 仓库(推荐)#

这是最省事的路径,不需要装任何 CLI,也不需要本地构建。

1. Fork 仓库#

把 memos-on-edgeone Fork 到你自己的 GitHub 账号。

2. 从 Git 仓库导入项目#

  1. 登录 EdgeOne 国内版控制台 | EdgeOne 国际版控制台
  2. 进入 边缘应用 → Pages(Makers)→ 创建项目
  3. 选择 从 Git 仓库导入
  4. 授权 GitHub,选择刚才 Fork 的仓库
  5. 构建配置会自动读取仓库根目录的 edgeone.json,一般不需要手改

edgeone.json 里的关键配置如下:

{
"buildCommand": "npm run build:web",
"installCommand": "npm install && cd web && npm install",
"outputDirectory": "./web/dist",
"nodeVersion": "22.11.0",
"cloudFunctions": {
"maxDuration": 120,
"externalNodeModules": ["@aws-sdk/client-s3", "@aws-sdk/s3-request-presigner"]
},
"rewrites": [{ "source": "/*", "destination": "/index.html" }]
}

注意 rewrites:前端是 SPA,所有未知路径都要回退到 index.html,/u/<username> 这类页面靠它才能正常打开。

3. 配置环境变量#

在 项目设置 → 环境变量 中添加:

Terminal window
JWT_SECRET=<你的密钥>
INSTANCE_NAME=memos-on-edgeone
APP_VERSION=1.0.0
BLOB_STORE_NAME=memos

JWT_SECRET 是唯一必填项,用来签发登录态。生成一个足够随机的值:

Terminal window
# macOS / Linux
openssl rand -base64 32
# Windows PowerShell
[Convert]::ToBase64String([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))
Warning

不要用示例值或短字符串。JWT_SECRET 泄露等于任何人都能伪造登录令牌。

4. 访问并注册管理员#

部署成功后(通常 2~5 分钟),打开 EdgeOne 分配的默认域名。

第一个完成注册的用户会自动成为管理员(ADMIN),之后的注册才是普通用户。所以部署完成后请立刻完成管理员注册,再到「设置 → 实例设置」里打开「禁止用户注册」,避免被别人抢先注册成管理员。

Tip

访问 https://你的域名/api/v1/health,返回 {"status":"ok"} 说明 Cloud Functions 已经正常工作;如果返回 HTML 页面或 404,说明 Functions 还没部署成功或路由没命中。

5. 绑定自定义域名(可选)#

在 项目 → 域名管理 → 添加自定义域名 中填入你的域名,按提示在 DNS 服务商处添加对应的 CNAME 记录,证书可在控制台申请免费证书或使用托管证书。

部署方式二:本地开发 + 推送自动部署#

想在本地改代码再部署,按这套流程走。

1. 安装 EdgeOne CLI 并登录#

Terminal window
npm install -g edgeone
edgeone -v # 确认安装成功
edgeone login # 浏览器弹窗授权;命令行会询问站点,选 China 或 Global
edgeone whoami # 查看当前账号

2. 克隆并安装依赖#

Terminal window
git clone https://github.com/你的用户名/memos-on-edgeone.git
cd memos-on-edgeone
npm install
cd web && npm install && cd ..

根目录和 web 是两个独立的 npm 工程,EdgeOne 的安装命令也正是分两步安装的。

3. 配置本地环境变量#

Terminal window
cp .dev.vars.example .dev.vars # Windows: copy .dev.vars.example .dev.vars

编辑 .dev.vars,至少填入 JWT_SECRET:

BLOB_STORE_NAME=memos
JWT_SECRET=your-super-secret-jwt-key-here
INSTANCE_NAME=memos-on-edgeone
APP_VERSION=1.0.0

.dev.vars 已在 .gitignore 中,不要把它提交到仓库。

4. 启动本地开发服务#

需要两个终端:

Terminal window
# 终端 1:后端 Cloud Functions
npm run dev
# 终端 2:前端 Vite 开发服务器
npm run dev:web

edgeone makers dev 默认在 8088 端口同时提供前端页面与 Functions 服务。如果想把控制台已配置的环境变量同步到本地,可以执行 edgeone makers link 关联项目,或者用 edgeone makers env pull 拉取环境变量。

5. 推送触发自动部署#

Terminal window
git push origin main

EdgeOne 检测到推送后会自动安装依赖、执行 npm run build:web、把前端部署到 CDN、把 Functions 部署到边缘节点,并更新域名指向。

部署方式三:CLI 直接上传#

不想每次都推 Git,也可以直接从本地上传构建产物:

Terminal window
edgeone makers deploy # 生产环境
edgeone makers deploy -e preview # 预览环境

CI 里也可以用 API Token 免交互部署:

Terminal window
edgeone makers deploy -n my-memos -t $EDGEONE_API_TOKEN

部署后的常用配置#

这些都在前端的「设置」里完成,不需要重新部署。

附件存储#

默认附件也存在 Blob 里(key 为 attachments/<uid>/<filename>)。需要注意 Cloud Functions 对请求体超过 6 MB 会直接拒绝,所以大附件走的是预签名 URL 直传:函数只签发一个短期令牌,浏览器把文件字节直接 PUT 到存储,再回调 POST /api/v1/attachments/complete 落库,绕开了函数体积限制。

想把附件搬到自己的 S3 兼容存储,可以在 设置 → 存储 里选择 S3 并填写 endpoint、region、bucket、Access Key / Secret Key。切换后新旧附件都能正常读取:每条附件记录都会写入 storage_type 标记(BLOB 或 S3),读写时据此解析到对应后端。

如果连数据库也要一起搬到 S3,那就在环境变量里设置 STORAGE_TYPE=s3 加上一组 S3_* 变量,此时 Blob 不再承担任何数据:

STORAGE_TYPE=s3
S3_ENDPOINT=https://s3.your-provider.com
S3_REGION=auto
S3_BUCKET=your-bucket-name
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_FORCE_PATH_STYLE=true # MinIO 等需要路径风格的服务保持 true

AI 语音转写#

在 设置 → AI 里新增一个 OpenAI 兼容的自定义 API(endpoint + API Key),指定为转写模型(如 whisper-1),录音文件就能直接转成文字写进备忘录。API Key 存在 Blob 的 instance/settings/AI 里,接口返回时会做脱敏。

关闭注册#

设置 → 实例设置 中打开「禁止用户注册」和「禁止密码登录」(如需配合 OAuth 登录)。

环境变量速查#

变量说明必填默认值
JWT_SECRETJWT 签名密钥是-
BLOB_STORE_NAMEBlob 命名空间名否memos
STORAGE_TYPEblob | s3否blob
S3_ENDPOINTS3 端点S3 模式必填-
S3_REGIONS3 区域否auto
S3_BUCKET桶名S3 模式必填-
S3_ACCESS_KEY_IDAccess KeyS3 模式必填-
S3_SECRET_ACCESS_KEYSecret KeyS3 模式必填-
S3_FORCE_PATH_STYLE强制路径风格否true
INSTANCE_NAME实例名称否memos-on-edgeone
APP_VERSION应用版本否1.0.0

备份与迁移#

因为所有表就是 Blob 里的 JSON 文档,备份特别直白:把 db/*.json 和 instance/settings/* 原样导出来存好,恢复时再传回去即可——不用像 SQLite 那样做一致性快照。

Note

Blob 官方定位是”运行时数据存储”,控制台只提供只读浏览(看得到命名空间和目录结构,但不能下载),命名空间创建和数据操作都要通过 SDK 完成。也就是说大批量导出/迁移建议用 @edgeone/pages-blob 配合 projectId + API Token 从外部脚本访问。

Blob 免费版单值上限 25 MB,db/memo.json 会随着笔记数量增长而变大。个人使用几千条笔记完全没问题;如果要放大量带附件的内容,建议尽早按上面的方式把存储切到 S3。

常见问题#

Q:一定要用 EdgeOne 吗?能用 Cloudflare 吗? A:可以,这是两个独立项目。Cloudflare 版用 D1 + R2,EdgeOne 版用 Blob。

Q:构建失败了怎么办? A:先看部署日志。常见原因是 Node 版本(必须是 22.11.0)或依赖没装全——根目录和 web 都要 npm install。如果日志里出现 @aws-sdk/* 相关的打包错误,注意 edgeone.json 里已经把它们放进 cloudFunctions.externalNodeModules,不要删掉。

Q:页面刷新后 404? A:edgeone.json 里的 rewrites 被覆盖了。SPA 需要 /* → /index.html 的回退规则。

Q:注册接口报 500? A:多半是 JWT_SECRET 没配或为空。

Q:为什么我的 KV 明明申请通过了却用不了? A:回到 为什么不用 KV 那一节——KV 当前仅在 Edge Functions 运行时可用,而这个项目的后端跑在 Cloud Functions 上。

小结#

memos-on-edgeone 的价值在于把部署成本压到了最低:不用买服务器,不用建数据库,不用初始化,关联 GitHub、填一个 JWT_SECRET 就能跑。存储选型上的取舍也很明确——因为国内版 KV 需要申请审核、且仅限 Edge Functions、只有最终一致性,所以用户与配置数据统一放进了零申请、Cloud Functions 可用、支持单次强一致读的 Blob。

如果你喜欢这种”能托管就不运维”的思路,可以看看我博客里的其他 EdgeOne 折腾记录。项目开源,MIT 协议,欢迎提 Issue 和 PR。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
Memos on EdgeOne 部署教程:零数据库,纯 Blob 存储
https://blog.mooncc.cn/posts/memos-on-edgeone-deploy/
作者
MoonCC
发布于
2026-10-05
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
MoonCC
Hello, I'm MoonCC.
公告
欢迎来到我的博客!采用 Astro & Firefly Theme,持续更新中~
分类
标签
最新动态
站点统计
文章
9
分类
4
标签
10
总字数
22,492
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
EdgeOne Pages
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录