|
| 1 | +# 部署文档 |
| 2 | + |
| 3 | +本项目基于 **Cloudflare** 全家桶构建: |
| 4 | + |
| 5 | +- **后端**:Cloudflare Workers(Hono 框架) |
| 6 | +- **数据库**:Cloudflare D1(SQLite) |
| 7 | +- **对象存储**:Cloudflare R2 |
| 8 | +- **前端**:Cloudflare Pages(React + Vite) |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## 目录 |
| 13 | + |
| 14 | +1. [前置条件](#1-前置条件) |
| 15 | +2. [首次手动部署(初始化)](#2-首次手动部署初始化) |
| 16 | + - 2.1 [创建 D1 数据库](#21-创建-d1-数据库) |
| 17 | + - 2.2 [创建 R2 存储桶](#22-创建-r2-存储桶) |
| 18 | + - 2.3 [配置 wrangler.toml](#23-配置-wranglertoml) |
| 19 | + - 2.4 [初始化数据库表结构](#24-初始化数据库表结构) |
| 20 | + - 2.5 [部署后端 Worker](#25-部署后端-worker) |
| 21 | + - 2.6 [部署前端到 Pages](#26-部署前端到-pages) |
| 22 | + - 2.7 [配置 Service Binding](#27-配置-service-binding) |
| 23 | +3. [GitHub Actions 自动部署](#3-github-actions-自动部署) |
| 24 | + - 3.1 [创建 Cloudflare API Token](#31-创建-cloudflare-api-token) |
| 25 | + - 3.2 [配置 GitHub Secrets](#32-配置-github-secrets) |
| 26 | + - 3.3 [触发自动部署](#33-触发自动部署) |
| 27 | +4. [环境变量说明](#4-环境变量说明) |
| 28 | +5. [常见问题](#5-常见问题) |
| 29 | + |
| 30 | +--- |
| 31 | + |
| 32 | +## 1. 前置条件 |
| 33 | + |
| 34 | +| 工具 | 版本要求 | 说明 | |
| 35 | +|------|----------|------| |
| 36 | +| Node.js | >= 18 | 建议使用 20 LTS | |
| 37 | +| npm | >= 9 | 随 Node.js 安装 | |
| 38 | +| Wrangler CLI | >= 3 | Cloudflare 官方命令行工具 | |
| 39 | +| Cloudflare 账号 | - | 需开通 Workers、D1、R2、Pages | |
| 40 | + |
| 41 | +安装 Wrangler: |
| 42 | + |
| 43 | +```bash |
| 44 | +npm install -g wrangler |
| 45 | +wrangler login |
| 46 | +``` |
| 47 | + |
| 48 | +--- |
| 49 | + |
| 50 | +## 2. 首次手动部署(初始化) |
| 51 | + |
| 52 | +> 首次部署必须手动完成,主要是创建云端资源并获取对应 ID 填入配置。 |
| 53 | +
|
| 54 | +### 2.1 创建 D1 数据库 |
| 55 | + |
| 56 | +```bash |
| 57 | +cd backend |
| 58 | +npm run db:create |
| 59 | +``` |
| 60 | + |
| 61 | +输出示例: |
| 62 | + |
| 63 | +``` |
| 64 | +✅ Successfully created DB 'memos_db' |
| 65 | +{ |
| 66 | + "uuid": "e03f026e-xxxx-xxxx-xxxx-xxxxxxxxxxxx", |
| 67 | + ... |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +复制输出中的 `uuid`,填入 `backend/wrangler.toml`: |
| 72 | + |
| 73 | +```toml |
| 74 | +[[d1_databases]] |
| 75 | +binding = "DB" |
| 76 | +database_name = "memos_db" |
| 77 | +database_id = "<你的 uuid>" |
| 78 | +``` |
| 79 | + |
| 80 | +### 2.2 创建 R2 存储桶 |
| 81 | + |
| 82 | +```bash |
| 83 | +wrangler r2 bucket create memos |
| 84 | +``` |
| 85 | + |
| 86 | +> R2 存储桶名称须全局唯一,如 `memos` 已被占用可改为 `memos-yourname`,同步修改 `wrangler.toml` 中的 `bucket_name`。 |
| 87 | +
|
| 88 | +### 2.3 配置 wrangler.toml |
| 89 | + |
| 90 | +`backend/wrangler.toml` 完整示例: |
| 91 | + |
| 92 | +```toml |
| 93 | +name = "memos-api" |
| 94 | +main = "src/index.js" |
| 95 | +compatibility_date = "2024-01-15" |
| 96 | +compatibility_flags = ["nodejs_compat"] |
| 97 | + |
| 98 | +[vars] |
| 99 | +TIMEZONE = "Asia/Shanghai" |
| 100 | + |
| 101 | +[[d1_databases]] |
| 102 | +binding = "DB" |
| 103 | +database_name = "memos_db" |
| 104 | +database_id = "<你的 D1 数据库 ID>" |
| 105 | + |
| 106 | +[[r2_buckets]] |
| 107 | +binding = "BUCKET" |
| 108 | +bucket_name = "memos" |
| 109 | +``` |
| 110 | + |
| 111 | +### 2.4 初始化数据库表结构 |
| 112 | + |
| 113 | +```bash |
| 114 | +cd backend |
| 115 | +npm run db:init |
| 116 | +``` |
| 117 | + |
| 118 | +该命令执行 `schema.sql`,在远程 D1 数据库中创建所有表。 |
| 119 | + |
| 120 | +> 本地开发时使用 `npm run db:local` 初始化本地数据库。 |
| 121 | +
|
| 122 | +### 2.5 部署后端 Worker |
| 123 | + |
| 124 | +```bash |
| 125 | +cd backend |
| 126 | +npm run deploy |
| 127 | +``` |
| 128 | + |
| 129 | +部署成功后,Wrangler 会输出 Worker 的访问地址,例如: |
| 130 | + |
| 131 | +``` |
| 132 | +https://memos-api.<your-subdomain>.workers.dev |
| 133 | +``` |
| 134 | + |
| 135 | +记录该地址,后续配置前端 fallback URL 时使用。 |
| 136 | + |
| 137 | +### 2.6 部署前端到 Pages |
| 138 | + |
| 139 | +**方式一:通过 Wrangler CLI(推荐)** |
| 140 | + |
| 141 | +```bash |
| 142 | +cd frontend |
| 143 | +npm ci |
| 144 | +npm run build |
| 145 | +wrangler pages deploy dist --project-name=memos-frontend |
| 146 | +``` |
| 147 | + |
| 148 | +首次执行时 Wrangler 会自动创建 Pages 项目。 |
| 149 | + |
| 150 | +**方式二:通过 Cloudflare Dashboard** |
| 151 | + |
| 152 | +1. 登录 [Cloudflare Dashboard](https://dash.cloudflare.com) |
| 153 | +2. 进入 **Workers & Pages → Create → Pages → Connect to Git** |
| 154 | +3. 选择本仓库,设置构建配置: |
| 155 | + - **Framework preset**:None |
| 156 | + - **Build command**:`cd frontend && npm ci && npm run build` |
| 157 | + - **Build output directory**:`frontend/dist` |
| 158 | + - **Root directory**:`/` |
| 159 | + |
| 160 | +### 2.7 配置 Service Binding |
| 161 | + |
| 162 | +Service Binding 让前端 Pages 直接内部调用后端 Worker,无需跨域请求,性能更好。 |
| 163 | + |
| 164 | +1. 进入 Cloudflare Dashboard → **Workers & Pages** → 选择前端 Pages 项目 |
| 165 | +2. 点击 **Settings → Functions** |
| 166 | +3. 在 **Service bindings** 中添加: |
| 167 | + - **Variable name**:`BACKEND` |
| 168 | + - **Service**:选择你的 Worker(`memos-api`) |
| 169 | + - **Environment**:`production` |
| 170 | +4. 点击 **Save** |
| 171 | + |
| 172 | +> 配置 Service Binding 后,`frontend/functions/_middleware.js` 会自动使用内部调用,无需配置 CORS。 |
| 173 | +
|
| 174 | +--- |
| 175 | + |
| 176 | +## 3. GitHub Actions 自动部署 |
| 177 | + |
| 178 | +每次推送到 `main` 分支时,工作流会自动: |
| 179 | +1. 部署后端 Worker |
| 180 | +2. 构建前端并部署到 Cloudflare Pages |
| 181 | + |
| 182 | +### 3.1 创建 Cloudflare API Token |
| 183 | + |
| 184 | +1. 进入 [Cloudflare API Tokens](https://dash.cloudflare.com/profile/api-tokens) |
| 185 | +2. 点击 **Create Token → Custom Token** |
| 186 | +3. 配置权限: |
| 187 | + |
| 188 | +| 权限类型 | 资源 | 操作 | |
| 189 | +|----------|------|------| |
| 190 | +| Account | Cloudflare Pages | Edit | |
| 191 | +| Account | Workers Scripts | Edit | |
| 192 | +| Account | Workers D1 | Edit | |
| 193 | +| Account | Workers R2 Storage | Edit | |
| 194 | +| Zone | Workers Routes | Edit(可选,如需自定义域名) | |
| 195 | + |
| 196 | +4. 点击 **Continue to summary → Create Token**,复制 Token(只显示一次) |
| 197 | + |
| 198 | +### 3.2 配置 GitHub Secrets |
| 199 | + |
| 200 | +进入 GitHub 仓库 → **Settings → Secrets and variables → Actions → New repository secret**,添加以下 3 个 Secret: |
| 201 | + |
| 202 | +| Secret 名称 | 说明 | 获取方式 | |
| 203 | +|-------------|------|----------| |
| 204 | +| `CLOUDFLARE_API_TOKEN` | 上一步创建的 API Token | 见 3.1 | |
| 205 | +| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare 账号 ID | Dashboard 右侧边栏 → Account ID | |
| 206 | +| `CF_PAGES_PROJECT_NAME` | Pages 项目名称 | 如 `memos-frontend` | |
| 207 | + |
| 208 | +### 3.3 触发自动部署 |
| 209 | + |
| 210 | +**自动触发**:推送代码到 `main` 分支即自动触发。 |
| 211 | + |
| 212 | +```bash |
| 213 | +git add . |
| 214 | +git commit -m "your changes" |
| 215 | +git push origin main |
| 216 | +``` |
| 217 | + |
| 218 | +**手动触发**:进入 GitHub 仓库 → **Actions → Deploy to Cloudflare → Run workflow**。 |
| 219 | + |
| 220 | +--- |
| 221 | + |
| 222 | +## 4. 环境变量说明 |
| 223 | + |
| 224 | +### 后端(wrangler.toml `[vars]`) |
| 225 | + |
| 226 | +| 变量名 | 默认值 | 说明 | |
| 227 | +|--------|--------|------| |
| 228 | +| `TIMEZONE` | `Asia/Shanghai` | 服务端时区,影响 RSS 时间显示 | |
| 229 | + |
| 230 | +### 前端(无需额外环境变量) |
| 231 | + |
| 232 | +前端通过 Service Binding 或相对路径调用后端 API,无需配置 API 地址。 |
| 233 | + |
| 234 | +如需修改 fallback 后端地址(未配置 Service Binding 时),编辑: |
| 235 | + |
| 236 | +```js |
| 237 | +// frontend/functions/_middleware.js 第 43 行 |
| 238 | +const backendUrl = 'https://memos-api.your-domain.workers.dev' + url.pathname + url.search; |
| 239 | +``` |
| 240 | + |
| 241 | +--- |
| 242 | + |
| 243 | +## 5. 常见问题 |
| 244 | + |
| 245 | +### Q: 部署后上传文件报 500 错误 |
| 246 | + |
| 247 | +**原因**:R2 bucket 未绑定或 bucket 名称不匹配。 |
| 248 | + |
| 249 | +**排查**: |
| 250 | +1. 确认 `wrangler.toml` 中 `bucket_name` 与 Cloudflare Dashboard 中 R2 bucket 名称一致 |
| 251 | +2. 重新执行 `npm run deploy` |
| 252 | + |
| 253 | +### Q: 前端访问 API 报 CORS 错误 |
| 254 | + |
| 255 | +**原因**:未配置 Service Binding,且 fallback URL 指向错误地址。 |
| 256 | + |
| 257 | +**解决**:按照 [2.7 节](#27-配置-service-binding) 配置 Service Binding,或修改 `_middleware.js` 中的 fallback URL。 |
| 258 | + |
| 259 | +### Q: GitHub Actions 部署失败,提示 `authentication error` |
| 260 | + |
| 261 | +**原因**:API Token 权限不足或 Secret 配置错误。 |
| 262 | + |
| 263 | +**排查**: |
| 264 | +1. 检查 GitHub Secrets 中三个变量是否正确填写(无多余空格) |
| 265 | +2. 检查 API Token 权限是否包含 Pages Edit 和 Workers Scripts Edit |
| 266 | + |
| 267 | +### Q: 数据库迁移 / 重置 |
| 268 | + |
| 269 | +> ⚠️ 以下操作会清空数据,请先备份。 |
| 270 | +
|
| 271 | +```bash |
| 272 | +# 仅在需要重建表结构时执行 |
| 273 | +cd backend |
| 274 | +wrangler d1 execute memos_db --command="DROP TABLE IF EXISTS memos" --remote |
| 275 | +npm run db:init |
| 276 | +``` |
| 277 | + |
| 278 | +### Q: 本地开发 |
| 279 | + |
| 280 | +```bash |
| 281 | +# 终端 1:启动后端(本地 D1 + R2 模拟) |
| 282 | +cd backend |
| 283 | +npm run dev |
| 284 | + |
| 285 | +# 终端 2:启动前端(代理到本地后端 :8787) |
| 286 | +cd frontend |
| 287 | +npm install |
| 288 | +npm run dev |
| 289 | +``` |
| 290 | + |
| 291 | +前端开发服务器运行在 `http://localhost:5173`,API 请求自动代理到 `http://127.0.0.1:8787`。 |
0 commit comments