Cloudflare Wrangler 实战:工具站的部署与维护
这篇笔记整理我用 Cloudflare Wrangler 部署和维护三个二级域名工具站的过程:
mail.5imcs.com、paste.5imcs.com 与 img.5imcs.com。
重点不是罗列命令,而是建立一套可复用的操作模型:本地项目、wrangler.toml、Cloudflare
资源绑定、自定义域名、部署版本和运行日志之间要保持一致。
其中 mail.5imcs.com 和 paste.5imcs.com 是两个完整案例;
img.5imcs.com 暂作为图床入口记录。
二级域名入口
从 Notes & Logs 进入此页后,可直接跳转到常用工具站点。
Cloud Mail
mail.5imcs.com
域名邮箱与收信服务,基于 Cloudflare Workers、D1、KV、R2、Email Routing 和前端静态资源部署。 来源:maillab/cloud-mail
打开 MailPastebin Worker
paste.5imcs.com
文本、代码片段、短链接和较大内容的分享工具,使用 Worker API、静态前端、KV、R2 和 Cron。 来源:SharzyL/pastebin-worker
打开 PasteCloudFlare ImgBed
img.5imcs.com
图床与文件托管入口,用于图片上传、对象存储和外链访问。 来源:MarSeventh/CloudFlare-ImgBed
打开 ImgBed1. 先把 Wrangler 想清楚
Wrangler 是 Cloudflare Workers 的本地命令行工具。通过它可以完成登录、构建、dry-run、部署、查看日志、创建 KV/R2/D1 资源、绑定静态资源、配置 Cron、管理版本和回滚等操作。
我现在更倾向于把它理解成 Workers 的“部署控制台”:
- 本地写代码,项目内安装 Wrangler。
- 用
wrangler.toml描述 Worker 名称、入口文件、运行时兼容日期、资源绑定和访问域名。 - 用
deploy --dry-run先检查构建和配置。 - 用
deploy发布到 Cloudflare。 - 上线后用
tail看日志,用deployments、versions、rollback处理版本。
最容易误解的一点是:Wrangler 不只是“上传代码”。如果代码里写了 env.PB.get(...),那么
PB 必须在 wrangler.toml 里绑定到一个 KV namespace;如果代码里写了
env.R2.put(...),R2 必须绑定到一个 R2 bucket。binding 名称是运行时变量名,不是资源展示名。
2. 安装、登录与基本命令
Cloudflare 官方更推荐在项目中本地安装 Wrangler,而不是长期依赖全局安装。这样每个项目可以使用自己的 Wrangler 版本,项目脚本也更容易复现。
npx wrangler <command>
pnpm wrangler <command>
yarn wrangler <command>
在使用 pnpm 的项目里,我通常先确认版本和登录状态:
pnpm wrangler --version
pnpm wrangler whoami
如果尚未登录,运行:
pnpm wrangler login
该命令会打开浏览器完成 Cloudflare 授权。授权后,本地 Wrangler 才能创建资源、部署 Worker、查看日志和执行回滚。
常用命令可以先记住这一组:
pnpm wrangler --version
pnpm wrangler whoami
pnpm wrangler deploy --dry-run
pnpm wrangler deploy
pnpm wrangler tail
如果项目已经在 package.json 里定义了脚本,应优先使用项目脚本。例如:
{
"scripts": {
"deploy": "wrangler deploy",
"build": "wrangler deploy --dry-run --outdir=dist"
}
}
对应命令为:
pnpm run build
pnpm run deploy
3. 读懂 wrangler.toml
wrangler.toml 是 Worker 的部署说明书。它把代码入口、运行时、域名、资源绑定和环境变量放在同一个配置文件中。一个最小结构如下:
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2026-06-02"
workers_dev = true
[[routes]]
pattern = "example.com"
custom_domain = true
[[kv_namespaces]]
binding = "MY_KV"
id = "<kv_namespace_id>"
[[r2_buckets]]
binding = "MY_R2"
bucket_name = "my-r2-bucket"
[vars]
PUBLIC_SETTING = "not-secret"
| 字段 | 作用 |
|---|---|
name |
Cloudflare 里的 Worker 名称。 |
main |
Worker 入口文件,常见形式是 src/index.ts、src/index.js 或 worker/index.ts。 |
compatibility_date |
Workers 运行时兼容日期。它不是部署日期,而是决定启用哪些运行时行为。 |
workers_dev |
是否启用 *.workers.dev 访问入口。 |
routes |
绑定自定义域名或路由。custom_domain = true 表示直接把 Worker 挂到该域名。 |
kv_namespaces |
把 Cloudflare KV namespace 绑定给 Worker。 |
r2_buckets |
把 R2 bucket 绑定给 Worker。 |
d1_databases |
把 D1 数据库绑定给 Worker。 |
assets |
上传并绑定静态前端目录。 |
triggers |
声明 Cron 定时触发器。 |
vars |
普通环境变量,适合保存非敏感配置。 |
binding 是什么
binding 是代码里的变量名,不是 Cloudflare 资源名。例如:
[[kv_namespaces]]
binding = "PB"
id = "<kv_namespace_id>"
这表示 Worker 代码里可以这样访问 KV:
await env.PB.get("some-key")
如果把配置改成 binding = "PASTE_KV",而代码仍然读取 env.PB,部署可能通过,但运行时会报错。
所以配置资源时应先搜索代码中的 env.,再决定 binding 名称。
vars 与 secrets 的区别
[vars] 会写进配置文件,适合公开 URL、标题、开关、默认过期时间等非敏感值。敏感值应使用 Wrangler secret:
pnpm wrangler secret put JWT_SECRET
pnpm wrangler secret put API_TOKEN
这样 secret 不会出现在 wrangler.toml 中。如果某个项目已经把敏感值写入配置文件,后续应逐步迁移到 secret,并避免提交到公开仓库。
4. dry-run、部署与回滚
正式部署前先运行:
pnpm wrangler deploy --dry-run
dry-run 会构建、打包并检查配置,但不会把当前版本切到线上。重点看这些输出:
- Worker 名称是否正确。
- 入口文件是否正确。
- routes 或 custom domain 是否指向预期域名。
- KV、R2、D1、assets、AI 等 bindings 是否出现。
- 前端 build command 是否成功。
- 是否存在缺失资源、权限错误或语法错误。
带输出目录的 dry-run 常用于检查打包产物:
pnpm wrangler deploy --dry-run --outdir=dist
正式部署:
pnpm wrangler deploy
部署后立刻做三类检查:
pnpm wrangler tail
curl -I https://your-domain.example
curl https://your-domain.example/some-health-or-home-page
如果线上出现问题,优先考虑回滚 Worker 代码版本:
pnpm wrangler deployments
pnpm wrangler rollback
pnpm wrangler rollback <version_id>
回滚只处理 Worker 代码版本,不会自动回滚 D1、KV、R2 中的数据。如果新版本改了数据库结构或对象格式,回滚前要判断旧代码是否还能读取新数据。
5. Cloudflare 常用资源速查
Custom Domain
把 Worker 挂到自己的域名上:
[[routes]]
pattern = "paste.5imcs.com"
custom_domain = true
也可以写成数组形式:
routes = [
{ pattern = "mail.5imcs.com", custom_domain = true }
]
部署后 Cloudflare 会处理路由和证书。刚绑定后如果短时间内 SSL 异常,先等待证书和边缘网络传播,再检查 Dashboard 状态。
KV
KV 适合保存小数据、元数据、配置和短文本。创建 namespace:
pnpm wrangler kv namespace create PB
绑定示例:
[[kv_namespaces]]
binding = "PB"
id = "<kv_namespace_id>"
KV 是全球分布式读优化存储,写入和列表结果可能存在短暂延迟。删除验证时,不要只看 list,也要直接访问具体 key 或业务 URL。
R2
R2 适合保存附件、大 paste、图片和二进制对象。创建 bucket:
pnpm wrangler r2 bucket create my-bucket
绑定示例:
[[r2_buckets]]
binding = "R2"
bucket_name = "my-bucket"
R2 bucket 默认不是公开网站。Worker 通过 binding 访问对象,再由 Worker 决定是否把内容返回给用户。
D1
D1 是 Cloudflare 的 serverless SQL 数据库。创建数据库:
pnpm wrangler d1 create cloud-mail-db
绑定示例:
[[d1_databases]]
binding = "db"
database_name = "cloud-mail-db"
database_id = "<d1_database_id>"
初始化或执行 SQL 通常使用:
pnpm wrangler d1 execute cloud-mail-db --remote --file ./schema.sql
具体 SQL 文件名要以项目实际迁移脚本为准。
Static Assets
如果 Worker 同时服务前端页面,可以配置:
[assets]
directory = "./dist"
binding = "ASSETS"
not_found_handling = "single-page-application"
run_worker_first = true
directory是前端构建产物目录。binding是代码里访问静态资源的变量名。not_found_handling = "single-page-application"适合 Vue/React 单页应用。run_worker_first = true表示请求先经过 Worker,再决定是否交给静态资源。
Cron Triggers
Cron 用于定时执行 Worker 的 scheduled handler:
[triggers]
crons = ["0 0 * * *"]
要禁用 Cron,应明确设为空数组:
[triggers]
crons = []
只注释配置不一定能禁用已经部署的定时任务。
6. 案例一:mail.5imcs.com / Cloud Mail
mail.5imcs.com 来源于
maillab/cloud-mail。上游项目定位为基于 Cloudflare
的邮箱服务,支持用一个域名创建多个邮箱,并依赖 Workers、D1、KV、R2、Workers AI、Vue 和 Hono 等组件。
这个项目可以理解为 Worker 后端加 Vue 前端。核心配置结构如下,已去掉本地路径和资源 ID:
name = "cloud-mail"
main = "src/index.js"
compatibility_date = "2025-06-04"
keep_vars = true
workers_dev = true
routes = [
{ pattern = "mail.5imcs.com", custom_domain = true }
]
[[d1_databases]]
binding = "db"
database_name = "cloud-mail-db"
database_id = "<d1_database_id>"
[[kv_namespaces]]
binding = "kv"
id = "<kv_namespace_id>"
[[r2_buckets]]
binding = "r2"
bucket_name = "cloud-mail-r2"
[ai]
binding = "ai"
[assets]
binding = "assets"
directory = "./dist"
not_found_handling = "single-page-application"
run_worker_first = true
[triggers]
crons = ["*/30 * * * *", "0 16 * * *"]
[vars]
orm_log = false
domain = ["5imcs.com"]
admin = "<admin_email>"
# JWT secret should be configured with wrangler secret put, not stored here.
[build]
command = "pnpm --prefix ../mail-vue install && pnpm --prefix ../mail-vue run build"
这里最关键的是 binding 名称:
| 资源 | binding | 说明 |
|---|---|---|
| D1 | db |
保存邮箱和邮件相关结构化数据。 |
| KV | kv |
保存轻量状态、缓存或配置。 |
| R2 | r2 |
保存附件或较大对象。 |
| Static Assets | assets |
托管 Vue 前端构建产物。 |
| Workers AI | ai |
项目中的 AI binding。 |
推荐部署流程:
# 在 cloud-mail 的 Worker 项目目录中运行
pnpm install
pnpm wrangler whoami
pnpm wrangler deploy --dry-run
pnpm wrangler deploy
如果前端依赖构建脚本被 pnpm 拦截,应按 pnpm 提示批准必要 build scripts,再重新 dry-run。部署后检查:
curl -I https://mail.5imcs.com/
pnpm wrangler tail
数据库初始化要按项目提供的初始化入口或 SQL 执行。新环境至少要确认:
- D1 数据库已创建并绑定。
- KV namespace 已创建并绑定。
- R2 bucket 已创建并绑定。
domain = ["5imcs.com"]与实际域名一致。- 管理员邮箱正确。
- 注册策略和初始化入口不要长期保持开放。
Email Routing 接入思路:
- 在 Cloudflare 的
5imcs.com中启用 Email Routing。 - 创建或确认目标 Worker:
cloud-mail。 - 把 catch-all 路由到 Worker。
- 注意显式地址规则优先于 catch-all,例如显式管理员地址转发规则会先于 catch-all 生效。
- 发测试邮件,观察 Worker 日志和 Cloudflare Email Routing 状态。
7. 案例二:paste.5imcs.com / Pastebin Worker
paste.5imcs.com 来源于
SharzyL/pastebin-worker。上游项目是运行在
Cloudflare Workers 上的 pastebin,支持短链接、自定义链接、语法高亮、客户端加密、Markdown 渲染、URL shortener、HTTP API 和 CLI。
这个项目是 Worker API 加 React/Vite 前端。核心配置结构如下,已去掉资源 ID 和认证 hash:
name = "pastebin-worker"
compatibility_date = "2025-04-24"
workers_dev = false
main = "worker/index.ts"
[assets]
directory = "dist/frontend"
run_worker_first = true
binding = "ASSETS"
[triggers]
crons = ["0 0 * * *"]
[[routes]]
pattern = "paste.5imcs.com"
custom_domain = true
[[kv_namespaces]]
binding = "PB"
id = "<kv_namespace_id>"
[[r2_buckets]]
binding = "R2"
bucket_name = "pastebin-worker-r2"
[vars]
DEPLOY_URL = "https://paste.5imcs.com"
INDEX_PAGE_TITLE = "5imcs Pastebin"
BASIC_AUTH = { admin = "<bcrypt_hash>" }
R2_THRESHOLD = "20K"
R2_MAX_ALLOWED = "256M"
DEFAULT_EXPIRATION = "7d"
MAX_EXPIRATION = "90d"
这个配置里需要重点确认:
- 小 paste 存在 KV,binding 是
PB。 - 大内容存在 R2,binding 是
R2。 - 前端构建产物在
dist/frontend,binding 是ASSETS。 - Cron 用于清理过期 R2 对象。
BASIC_AUTH保护上传和历史管理入口,普通 paste 读取仍可公开。DEPLOY_URL必须与实际域名一致,否则生成链接会错。
推荐部署流程:
# 在 pastebin-worker 项目目录中运行
pnpm install
pnpm run build:frontend
pnpm run typecheck
pnpm run lint
pnpm test
pnpm wrangler deploy --dry-run --outdir=dist
pnpm wrangler deploy
如果只想按项目脚本做 dry-run:
pnpm run build
部署后检查:
curl -I https://paste.5imcs.com/
curl -I https://paste.5imcs.com/admin/history
pnpm wrangler tail
历史页应保持 Basic Auth 保护;匿名访问返回 401 是正常结果。上传类服务还要持续关注大小限制、默认过期时间、最大过期时间和 Cron 清理状态。
8. img.5imcs.com / CloudFlare ImgBed
img.5imcs.com 来源于
MarSeventh/CloudFlare-ImgBed。它承担图床和文件托管入口的角色,用于图片上传、对象存储和外链访问。
这篇笔记暂不展开它的完整部署过程。就站点组织而言,它和 mail、paste 构成一个小型个人工具集:邮箱收发、文本分享、图片托管分别由三个二级域名承载。后续如果图床的存储后端、访问权限或管理策略调整,应单独补充部署细节。
9. 日常运维清单
每次改配置或改代码,建议按这个顺序:
git status
pnpm install
pnpm run build
pnpm run test
pnpm wrangler deploy --dry-run
pnpm wrangler deploy
pnpm wrangler tail
同时检查:
- 自定义域名是否正常访问。
- 首页、API 或关键入口是否返回预期状态码。
- Worker 日志是否有运行时错误。
- KV、R2、D1、assets binding 名称是否和代码一致。
- secret 是否误写进
wrangler.toml。 - Cron 是否仍然需要保留。
workers_dev是否符合预期:公开调试可开启,正式服务也可以只走自定义域名。- 回滚前是否涉及数据库结构或对象格式变化。
10. 常见错误
binding 名字改错
现象:部署成功,但访问时报 Cannot read properties of undefined,或某个 env.X 不存在。
处理方式是回到代码里搜索 env.,确认 wrangler.toml 的 binding 名称一致。
dry-run 构建失败
wrangler deploy --dry-run 如果卡在 build command 或前端构建,应先单独跑前端构建命令:
pnpm --prefix ../mail-vue run build
pnpm run build:frontend
等前端构建通过后,再回到 Wrangler dry-run。
自定义域名刚部署后 SSL 异常
如果 curl 或浏览器提示 SSL 连接问题,先等几分钟,再检查 Cloudflare Dashboard 中 Worker route、custom domain 和证书状态。
KV 删除后列表里还看得到
KV 有最终一致性特征,列表结果可能短时间滞后。验证删除时,应直接请求业务 URL 或具体 key,不要只依赖 list。
Basic Auth 配置后没有生效
按顺序检查:
[vars] BASIC_AUTH是否存在。- bcrypt hash 是否正确。
- 代码实际保护的是哪些路径。
- 浏览器是否缓存了旧凭据。
11. 安全建议
- 不要把 API token、JWT secret、邮箱密码写进 Git。
- 生产 secret 使用
wrangler secret put。 - 公开站点的管理入口必须有认证。
- 上传类服务要限制大小、类型和过期策略。
- D1 schema 变更前先备份或记录迁移步骤。
- 回滚代码前,先判断数据结构是否兼容旧版本。
- Cloudflare OAuth、API token、账号权限不要在聊天或文档里明文复述。