name = "artalk-cf" main = "src/index.ts" compatibility_date = "2026-07-24" # ★ 证书探针需要 node:tls —— 只有它能在 Workers 里拿到**对端证书正文** # (`cloudflare:sockets` 的 Socket 接口没有 getPeerCertificate, # 实测线上只能确认「可达」但读不到 notAfter/SAN/issuer,那样证书管家等于瞎的)。 # 2026-08-04 之后的 compatibility_date 才默认带 nodejs_compat, # 本项目定在 2026-07-24,所以必须显式打开这个 flag。 compatibility_flags = ["nodejs_compat"] # --------------------------------------------------------------------------- # ★ Workers Cache —— 缓存 Worker 自己生成的响应(无需回源 fetch) # # 为什么必须开:Worker 位于 zone 缓存之前("Workers sits in front of cache"), # 所以 **zone 级 Cache Rules / Page Rules 对 Worker 响应完全无效**。 # 想让 /api/favicon 这类「Worker 直接返回」的响应被边缘缓存、从而不再执行 # Worker(省 KV 读 + 省 Worker 请求),唯一正解是这个 [cache] enabled。 # # 生效条件(缺一不可): # 1. 这里是 fetch 处理器(scheduled 等不参与缓存) # 2. 响应带可缓存的 Cache-Control(本项目已带 s-maxage=86400) # 3. 只缓存 GET/HEAD;带 Set-Cookie 的响应自动绕过 # 验证:连续两次 curl -I,应依次看到 cf-cache-status: MISS → HIT # --------------------------------------------------------------------------- [cache] enabled = true # --------------------------------------------------------------------------- # D1 (必须) 创建:npx wrangler d1 create artalk-cf # 然后把返回的 database_id 填到下面 # --------------------------------------------------------------------------- [[d1_databases]] binding = "DB" database_name = "artalk-cf" database_id = "78140776-2bfd-439a-8b05-c3eebe5d5b47" # --------------------------------------------------------------------------- # KV —— RSS 订阅数据(rss-robot 合并进来;KV 与 D1 共存于同一 Worker, # 数据沿用原 rss-robot-cf 的 namespace,零迁移) # --------------------------------------------------------------------------- [[kv_namespaces]] binding = "RSS_KV" id = "d7f86a0fb43f4450a10b786fc2635128" # --------------------------------------------------------------------------- # 普通变量(可以明文写在仓库里) # SITE_DEFAULT 默认站点名(博客里 site: '优世界',必须一致) # SITE_URL 默认站点地址,用于把相对 page_key 拼成完整 page_url # ADMIN_NAME/EMAIL 初始管理员(首次部署后调 /api/v2/setup 初始化) # ALLOWED_ORIGINS CORS 白名单,逗号分隔;**必须包含你博客的域名** # --------------------------------------------------------------------------- [vars] SITE_DEFAULT = "优世界" SITE_URL = "https://usj.cc" # 站内公开 API 基址(用于把 /api/favicon 这类相对地址拼成绝对地址,友圈页在博客域名下用) PUBLIC_API_BASE = "https://api.200181.xyz" ADMIN_NAME = "admin" ADMIN_EMAIL = "admin@200181.xyz" ALLOWED_ORIGINS = "https://usj.cc,https://www.usj.cc,https://post.usj.cc,https://artalk.200181.xyz,https://api.200181.xyz,http://localhost:1313,http://127.0.0.1:1313,http://localhost:8799,http://127.0.0.1:8799" ITEMS_PER_PAGE = "20" PENDING_DEFAULT = "false" # ---- RSS 订阅(rss-robot 合并进来的变量)---- # SCF_PROXY_URL 腾讯云 SCF 国内代理(scfapi.usj.cc),抓国内博客用 # FEEDS_URL 远程订阅源 JSON(回退用;KV 里已有 feeds_config,留空避免 Worker 自调用) # FEISHU_WEBHOOK_URL 飞书机器人 webhook(可选) SCF_PROXY_URL = "https://scfapi.usj.cc" FEEDS_URL = "" FEISHU_WEBHOOK_URL = "" # 文章编辑后端(自建 editor-api 容器,Worker 只做鉴权+反代)。 # 留空 = 模块自动禁用(/api/v2/editor/* 一律 503)。令牌另走 secret,别写这里。 # writeapi.usj.cc → 国内机 119.29.215.187 的 nginx 反代 → 127.0.0.1:8017 容器 # (换机时只改这条 + 新机重跑 deploy/editor-api/bootstrap.sh,域名指向新机即可) EDITOR_API_BASE = "https://writeapi.usj.cc" # ⚠️ 下面两个是机密,不要写在这里,用命令写入(详见「部署清单.md」第 4 步): # npx wrangler secret put TOKEN_SECRET # npx wrangler secret put ADMIN_PASSWORD # 本地开发用 .dev.vars 文件(见 .dev.vars.example) # --------------------------------------------------------------------------- # 邮件通知(可选) # # 为什么走 HTTP API 而不是 SMTP:**Cloudflare Workers 没有 TCP socket**, # 根本连不上 SMTP 服务器。(Cloudflare 2026-04 推出的原生 Email Service # 要 Workers Paid,本项目跑在免费版上。) # # 用 Resend:免费 3000 封/月(**每天上限 100 封**),本项目内置了日配额保护。 # 三个都走 secret / 环境变量: # npx wrangler secret put RESEND_API_KEY # re_xxxxxxxx(Resend 后台创建) # npx wrangler secret put MAIL_FROM # 形如 artalk # npx wrangler secret put MAIL_ADMIN # 管理员收件邮箱;不配则不发管理员通知 # # ⚠️ MAIL_FROM 里的域名必须先在 Resend 后台验证(加 SPF/DKIM 的 DNS 记录)。 # ⚠️ 三者任一缺失都只是「少发一类邮件」,不会影响评论提交 —— 邮件全程 try/catch。 # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # R2(可选)—— 评论里插图上传用。没建这个桶就自动禁用上传功能。 # 创建:npx wrangler r2 bucket create artalk-uploads # --------------------------------------------------------------------------- # [[r2_buckets]] # binding = "UPLOADS" # bucket_name = "artalk-uploads" # --------------------------------------------------------------------------- # 静态资源(必须) # public/sidebar/ = 官方管理后台(客户端用它打开 iframe:{server}/sidebar/) # public/dist/ = 官方客户端与插件,博客若想直接从服务端引也可以用 # 来源:Artalk v2.8.7 的 artalk_ui.tar.gz(预构建,无需前端构建环境) # --------------------------------------------------------------------------- [assets] directory = "public" binding = "ASSETS" # --------------------------------------------------------------------------- # 自定义域名 # 200181.xyz 的 NS 就在 Cloudflare 上,所以直接绑 artalk.200181.xyz 即可—— # custom_domain = true 会让 Cloudflare 自动建 DNS 记录 + 签 SSL 证书。 # # 对比:usj.cc 的 NS 在 DNSPod,所以它不能这么绑(绑了会破坏又拍云/EdgeOne 调度)。 # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # 自定义域名 # 2026-10-03 起统一到 api.200181.xyz(评论 /api/v2/* + 订阅 /api/* 同一 # Worker),artalk.200181.xyz 已解绑废弃。usj.cc 的 NS 在 DNSPod 不能这样绑。 # --------------------------------------------------------------------------- [[routes]] pattern = "api.200181.xyz" custom_domain = true # --------------------------------------------------------------------------- # 定时任务(合并 rss-robot 的抓取): # 0 * * * * RSS 轮转抓取(每小时一批,约 3 小时覆盖全部源) # 17 3 * * * 评论 GC(限流/验证码清理 + healthz 缓存刷新) # # ★ 2026-10-06 起,证书续期 cron(原 `10 4 * * *`)已移除: # 签发 + 部署整条链路搬到了国内机的 Docker 容器 `cn-certkeeper` # (见 deploy/cn-certkeeper/、函数版证书管家-方案.md 第九章)。 # 两处同时跑会**重复签发**(白耗 CA 配额)并争抢同一批站点部署, # 所以 Worker 侧只保留**只读**能力:证书状态查询 / 自检 / 后台。 # --------------------------------------------------------------------------- [triggers] crons = ["17 3 * * *", "0 * * * *"] # --------------------------------------------------------------------------- # 资源上限 —— ★ 免费版不支持,必须注释掉,否则**部署直接被拒** # # 2026-10-06 实测:wrangler deploy 报 # X [ERROR] A request to the Cloudflare API (.../workers/scripts/artalk-cf/versions) # failed. CPU limits are not supported for the Free plan. [code: 100328] # 注意:免费版不是「忽略」这个字段,而是**整个部署失败**, # 所以只要账号还在 Free plan,这段就必须保持注释。 # # ★ 免费版硬顶 CPU 10ms/请求(cron 同样 10ms)。实测一次签发的密码学 # 工作量:importKey 126µs + sign 84µs,一次签发约 10~12 次 JWS —— # 优化前 ≈3.3ms、缓存 CryptoKey 后 ≈1.4ms;乘 2~3 倍保守系数后 # 是 6.6~10ms vs 2.8~4.2ms,属于**擦边**而非「必然爆」。 # 但既然国内机本来就在跑,把签发搬过去更划算(还顺带绕开了 # 「CF 出口 IP 进不了 1Panel 白名单」「Worker 拿不到证书正文」两个坑)。 # → 决策见 函数版证书管家-方案.md 第九章(B+C 组合,不买 Paid)。 # --------------------------------------------------------------------------- [observability] enabled = true