# 部署清单(照着敲,约 10 分钟) 在 `artalk-cf` 目录里执行。**第 9 步(域名)有个必须先想清楚的坑**,其余都是机械操作。 需要你有的东西:Cloudflare 账号、Node.js(本机已有 22.x)、一个能连上 Cloudflare 的网络。 --- ## 0. 先确认环境 ```bash cd artalk-cf npm install node node_modules/typescript/bin/tsc --noEmit # 应该没有任何输出 ``` > 这台机器上 npm 可能被沙箱网络打断(`stub` 装不全)。若报 `Cannot find module`, > 重跑 `npm install` 直到 `node_modules/wrangler/package.json` 能读出版本号。 --- ## 1. 登录 Cloudflare ```bash npx wrangler login ``` 会弹出浏览器让你授权(这一步必须你自己点,我代不了)。 成功后会显示 `Successfully logged in.` 检查: ```bash npx wrangler whoami ``` --- ## 2. 建 D1 数据库 ```bash npx wrangler d1 create artalk-cf ``` 输出里会有一行 `database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"`,**复制它**。 --- ## 3. 把 database_id 填进配置 编辑 `wrangler.toml`,把这一行改掉: ```toml [[d1_databases]] binding = "DB" database_name = "artalk-cf" database_id = "00000000-0000-0000-0000-000000000000" # ← 换成刚才复制的那串 ``` 同一文件里再确认这几项是否符合你的情况: ```toml [vars] SITE_DEFAULT = "优世界" # 必须和博客 hugo.toml 里的 site 一致 SITE_URL = "https://usj.cc" ADMIN_NAME = "小赵" ADMIN_EMAIL = "z@usj.cc" ALLOWED_ORIGINS = "https://usj.cc,https://www.usj.cc,https://post.usj.cc,http://localhost:1313" ``` > `ALLOWED_ORIGINS` 少了博客域名的话,浏览器会因 CORS 拒绝评论请求(评论区一直转圈)。 --- ## 4. 写入两个机密(不要写进文件) ```bash # 签 token 的密钥:先生成一串随机的 node -e "console.log(require('crypto').randomBytes(48).toString('base64url'))" npx wrangler secret put TOKEN_SECRET # 粘贴上面那串 npx wrangler secret put ADMIN_PASSWORD # 输入你要用的后台密码 ``` (本地开发时改用 `.dev.vars`:`cp .dev.vars.example .dev.vars` 然后改值。) --- ## 5. 建表 ```bash npx wrangler d1 execute artalk-cf --remote --file=./schema.sql ``` 应该看到若干条 `🚣 Executed 8 commands` 之类的成功输出。 核对: ```bash npx wrangler d1 execute artalk-cf --remote --command \ "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;" ``` 应含:`captcha_challenges captcha_passes comments notifies pages rate_limits settings sites users votes` --- ## 6. 部署 ```bash npx wrangler deploy ``` 输出末尾会给一个地址: ``` Uploaded artalk-cf (x.xx sec) https://artalk-cf.<你的账号子域>.workers.dev ``` **把它记下来**,下面用 `` 代替。 --- ## 7. 导入评论数据(**必须在初始化管理员之前**) ```bash python tools/import_artrans.py # 默认只导「优世界」,跳过朋友那三个站 bash tools/import-out/run.sh --remote ``` 脚本会打印: ``` 源文件 4048 条,按站点筛选后 3440 条 -> 归入站点「优世界」 用户 491 个 页面 91 个 评论 3339 条(其中回复 1791 条) 跳过 101 条:page_key 为空 101、昵称或邮箱为空 0、id 非法 0 ``` 最后 `run.sh` 会跑一段自检,打印各表条数,对一下: `sites 1 / pages 91 / users 491 / comments 3339 / replies 1791` > ⚠️ **两个坑** > 1. `00-reset-and-site.sql` 会**清空 comments/pages/users/sites 四张表**—— > 所以它会把第 8 步建的管理员一起删掉。**顺序必须是「先导入、后初始化」**。 > 库里已有数据时也别再跑,会被清空。 > 2. `wrangler d1 execute --remote` 会先问一次确认,脚本里已经带了 `-y`。 > 如果你是手动逐条敲命令,漏了 `-y` 会直接报错退出。 --- ## 8. 初始化站点与管理员 ```bash curl -X POST /api/v2/setup ``` 期望返回: ```json {"msg":"Success","site":"优世界","admins":["admin@200181.xyz"],"reseted":false} ``` 它会建默认站点、把 `ADMIN_NAME/EMAIL/PASSWORD` 写成管理员(密码存 PBKDF2 哈希)。 **立刻验证管理员能登录**(账号名或邮箱都行): ```bash curl -X POST /api/v2/user/access_token \ -H 'Content-Type: application/json' \ -d '{"email":"admin","password":"你刚设的密码"}' ``` 返回里有 `"token":"..."` 就对了。**没有 token 说明第 4 步的密码没写进去。** > 忘了密码想重设:`curl -X POST "/api/v2/setup?force="`, > `TOKEN_SECRET` 就是你第 4 步写进去的那串(拿它当"部署密钥"用)。 --- ## 9. ★ 域名:这一步有个坑,先想清楚 ### 问题 **Cloudflare Worker 的自定义域名要求「域名的 NS 托管在 Cloudflare」。** 官方文档写得很明确:绑定自定义域名时,Cloudflare 会自动创建 DNS 记录和 SSL 证书—— 这需要 zone 在 Cloudflare 里。外部 DNS 用 CNAME 直接指过去,社区反馈是"各种奇奇怪怪的错误"。 而 **`usj.cc` 的 NS 在 DNSPod**(还挂着又拍云 + 腾讯云 EdgeOne 的调度)。 **千万不要为了评论 API 把整站 NS 搬去 Cloudflare**——那会把现有的国内双 CDN 链路一起弄坏。 ### 四个选项 | 选项 | 做法 | 代价 | 建议 | |---|---|---|---| | **A. 另用一个 CF 托管域名** | 用另一个域名(新注册的也行,便宜)把 NS 放到 Cloudflare,绑 `artalk-cf.<那个域名>` | 一年域名钱 | ✅ **推荐** | | B. 先用 workers.dev | 第 6 步的地址直接当正式地址 | **大陆访问不通**,只能自测 | 仅用于验证功能 | | C. DNSPod 加 CNAME | `artalk-cf` CNAME 到 `.workers.dev` | 官方不支持,可能不通/证书异常 | 可以试,别当正式方案 | | D. 整站 NS 迁到 Cloudflare | usj.cc → Cloudflare | **会破坏又拍云/EdgeOne 调度** | ❌ 不要 | ### 选了 A 之后怎么做 1. 新域名加进 Cloudflare → 按提示把 **NS 改到 Cloudflare** 2. 打开 `wrangler.toml`,取消注释并改成你的域名: ```toml [[routes]] pattern = "artalk-cf.你的域名" custom_domain = true ``` 3. `npx wrangler deploy` 4. 把域名加进 `ALLOWED_ORIGINS` 后再 deploy 一次 5. `curl https://artalk-cf.你的域名/api/v2/healthz` 应返回 `{"ok":true,...}` --- ## 10. 接到博客上(改一行 + 重新发布) 编辑 `E:\GitHub\blog\hugo.toml`: ```toml [params.artalk] server = "https://artalk-cf.你的域名" # ← 只改这一行 site = "优世界" ``` 然后按你平时的流程发布(写作后台点发布,或按 `hugo-writeserver-publish-ops` 里那套精确发布命令)。 **前端一个字符都不用动**——客户端调的就是 `${server}/api/v2/...`, `pageKey` 用 `.RelPermalink`(`/20210911.html`),和 D1 里的 `page_key` 完全对应。 --- ## 11. 验收 ```bash bash tools/smoke.sh https://artalk-cf.你的域名 ``` 然后拿 token 再跑一遍后台用例: ```bash TOKEN=$(curl -s -X POST https://artalk-cf.你的域名/api/v2/user/access_token \ -H 'Content-Type: application/json' \ -d '{"email":"z@usj.cc","password":"你的密码"}' | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>console.log(JSON.parse(s).token))") TOKEN=$TOKEN bash tools/smoke.sh https://artalk-cf.你的域名 ``` ### 手动验收清单 - [ ] 打开 `https://artalk-cf.你的域名/sidebar/` —— 能看到 Artalk 后台登录页 - [ ] 用邮箱 + 密码登录进去,能看到 **3339 条评论** - [ ] 打开博客任意一篇有评论的文章 —— 评论、回复层级、博主徽章都对 - [ ] 打开 `/comment.html`(994 条那篇)—— 分页/加载更多正常 - [ ] 发一条新评论 —— 立刻出现 - [ ] 后台改一条评论的置顶/审核状态 —— 前台刷新后生效 --- ## 12. 出问题怎么查 | 现象 | 原因 | 处理 | |---|---|---| | 评论区一直转圈 | CORS:`ALLOWED_ORIGINS` 没有博客域名 | 加上域名重新 deploy | | `401 Unauthorized` 登录失败 | 第 4 步密码没写进去 | `npx wrangler secret put ADMIN_PASSWORD` 后重新跑第 7 步 | | 后台打不开、404 | `/sidebar/` 静态资源没上传 | 确认 `artalk-cf/public/sidebar/index.html` 存在,重新 deploy | | 评论为空但后台有数据 | `page_key` 对不上 | 检查博客的 `pageKey` 是不是 `/xxx.html`;D1 里 `SELECT page_key FROM comments LIMIT 5` 比对 | | 部分回复层级错乱 | 导入时 rid 没回填 | 确认 `run.sh` 里 `04-rid-fix-*.sql` 都执行过了 | | 报 `Too many requests` | 限流生效(同 IP 60 秒 5 条) | 正常行为;管理员发表不受限 | | 前端弹版本不匹配黄条 | 客户端版本 ≠ 服务端上报版本 | 服务端固定报 `2.8.7`;若你把博客的 `Artalk.js` 升级了,改 `src/routes/public.ts` 的 `SERVER_API_VERSION` | | 大页面(994 条评论)超时 | Workers 免费版 CPU 10ms | 调小客户端 `pagination.pageSize`,或上 Workers Paid | 实时日志: ```bash npx wrangler tail ``` --- ## 附:也可以让我代跑 如果你不想自己敲,可以给我一个 **Cloudflare API Token**(权限只需 `Workers Scripts: Edit` + `D1: Edit` + `Account Settings: Read`),我可以直接执行第 2~8 步。 用完请立刻在 Cloudflare 后台把那个 token 删掉。 第 1 步(浏览器登录授权)和第 9 步(改 NS)无论如何都得你自己来。