我的 Cloudflare Worker 在国内访问不了的那些天,以及最终解决的全过程
当个人云盘只能让国外朋友用、而我自己打不开时,我以为是 GFW 的诅咒。折腾了一整天后我发现:换个域名就够了。
我的 Cloudflare Worker 在国内访问不了的那些天
以及最终解决的全过程
上个月我写过一篇文章叫《死在了网络上》。 说的是我好不容易把个人云盘搭好,结果自己却打不开。 国外朋友测试一切正常,我这边一直 Connection reset。 我以为这件事就到此为止了。
但这几天我又折腾了一整天,终于解决了。 这篇文章,我想完整记录下: 问题是什么 → 我试了什么 → 最终怎么解决的 → 整个过程。
重点不是技术细节,重点是"国内访问"这条主线。
⚠️ 隐私说明:本文所有地址、域名、Worker 名、目录名都用占位符代替,避免被 GFW 溯源后封杀。请根据自己实际情况替换。
第一章:问题的样子
部署明明成功了
我部署了一个基于 Cloudflare Worker 的个人云盘:
$ wrangler deploy
Uploaded <your-worker-name> (7.92 sec)
Published <your-worker-name> (7.92 sec)
https://<your-worker-name>.<your-account>.workers.dev
部署成功,Worker URL 显示正常,curl 测试返回 200。
理论上,我现在应该有一个属于自己的网盘了。
但是我打不开
我用浏览器打开那个 URL:
等待中...
等待中...
等待中...
ERR_CONNECTION_RESET
打不开。
我用手机 4G 测试:
等待中...
等待中...
等待中...
无法访问此网站
还是打不开。
我让一个国外朋友测试:
"完美!能打开,能登录,能上传!"
国外能访问,国内不行。
这就是问题
国内访问 Cloudflare *.workers.dev 子域,被 GFW 精准干扰。
不是 Cloudflare 服务挂了,不是 Worker 代码错了,不是 DNS 解析有问题。
就是 GFW 把 workers.dev 这个域名精准屏蔽了。
这就是问题的样子:
- ✅ 国外:完全正常
- ❌ 国内:完全打不开
一个只能让国外用户用的网盘,对自己来说有什么意义?
第二章:我的第一反应——认命
写《死在了网络上》
那篇文章里,我接受了现实:
"墙内用户用 VPN/4G 才能用" "死在了网络上,不是死在技术上"
写完后,这件事就这么搁置了。
毕竟:
- 代码已经写好了
- 服务已经跑起来了
- 国外朋友能用
- 我自己凑合着用 4G
我以为这就是终点了。
但有个念头一直在
但心里一直有个声音:
"如果不用
workers.dev子域呢?" "如果用我自己的域名呢?" "GFW 屏蔽的是workers.dev,还是 Cloudflare 整个生态?"
这才是这篇文章的核心问题。
第三章:真正的诊断
先问对问题
我之前一直在问"为什么访问不了",但没问对问题。
真正应该问的是:
"GFW 屏蔽的是什么?" 是
workers.dev这个域名? 还是 Cloudflare 整个 CDN 网络? 还是 Cloudflare 的某些 IP 段?
答案决定了解决方案。
三个层次的诊断
诊断 1:Cloudflare CDN 是否在国内被墙?
我先访问了一些 Cloudflare 的其他服务:
- ✅ Cloudflare 控制台:国内能访问
- ✅ Cloudflare R2 公开 URL:国内能访问
- ❌
*.workers.dev子域:国内被墙
结论:
Cloudflare 整体服务在国内能用,只有
workers.dev子域被精准干扰。
诊断 2:是 DNS 被污染,还是 IP 被屏蔽?
我用 dig 测试:
$ dig <your-worker-name>.<your-account>.workers.dev A +short
# 返回 Cloudflare 的 IP
$ dig <your-worker-name>.<your-account>.workers.dev AAAA +short
# 返回 Cloudflare 的 IPv6
DNS 解析正常。问题不在 DNS。
结论:
DNS 没被污染,是 TCP 连接的 IP 被屏蔽。
诊断 3:如果是 IP 被屏蔽,换个 IP 行不行?
关键思路:
workers.dev子域被墙 → 我用自己的域名行不行? 自己的域名指向 Cloudflare CDN → IP 段不同 → 可能不被屏蔽?
这就是我接下来要验证的核心假设。
第四章:解决方案的思路
关键发现
我意识到一件事:
GFW 屏蔽的是 *.workers.dev 这个域名,不是 Cloudflare 整个 CDN。
如果我用自己的域名,解析到 Cloudflare 的 CDN,理论上:
浏览器 → DNS(我的域名) → Cloudflare CDN(不同 IP 段)→ Worker
↑ ↑
不在 GFW 黑名单 不在 GFW 黑名单
这样就能绕过 GFW!
这个思路对吗?
需要验证。
验证方法:
- 注册一个自己的域名(指向 Cloudflare 名称服务器)
- 把域名解析到 Cloudflare
- 把 Worker 绑定到这个自定义域名
- 测试国内访问
如果假设成立,国内就能访问了。
我开始实施
接下来的问题:
- 怎么把 Worker 绑定到自定义域名?
- DNS 怎么配置?
- SSL 证书怎么申请?
Cloudflare 提供两种方式:
| 方式 | 优点 | 缺点 | |------|------|------| | Workers Routes | 灵活 | 需要手动配置 DNS | | Custom Domains | 自动管理 DNS | 要求域名"干净" |
我选 Custom Domains(最省心)。
但实际操作时,又是一堆坑……
第五章:实施过程
第 1 步:注册域名
我已经有了一个域名(<your-domain>),指向 Cloudflare 的名称服务器。
这一步之前就完成了。
第 2 步:写 wrangler.toml
name = "<your-worker-name>"
compatibility_date = "<your-compatibility-date>"
main = "src/index.ts"
assets = {
directory = "<path-to-ui-dashboard>",
binding = "ASSETS",
html_handling = "auto-trailing-slash",
not_found_handling = "single-page-application"
}
[[r2_buckets]]
binding = "<your-r2-binding-name>"
bucket_name = "<your-bucket-name>"
# ⭐ 关键配置:自定义域名
[[routes]]
pattern = "<your-domain>"
custom_domain = true
zone_name = "<your-domain>"
[observability]
enabled = true
⚠️ 上面的配置里,所有可能暴露身份的地方都用
<placeholder>标记。请根据自己实际情况替换。
第 3 步:从正确的目录部署
这里有个隐藏的坑:
<your-project-folder>/
├── wrangler.toml ← ❌ 这个不能用
└── template/
└── wrangler.toml ← ⭐ 真正的配置文件
我第一次从外层目录部署,wrangler 报错找不到 assets。
教训:找到真正可部署的根目录(带 assets 配置的那个)。
第 4 步:第一次 wrangler deploy
$ cd <your-project-folder>/<deploy-root>
$ wrangler deploy
⛅️ wrangler <latest-version>
───────────────────
🌀 Building list of assets...
✨ Read N files from the assets directory
Total Upload: <X> KiB / gzip: <Y> KiB
Uploaded <your-worker-name> (7.x sec)
✘ [ERROR] Hostname '<your-domain>' already has externally managed DNS records
(A, CNAME, etc). Delete them first or try a different hostname.
[code: 100117]
结果:
- ✅ Worker 代码上传成功
- ❌ Custom Domain 添加失败(域名已有 DNS 记录)
第 5 步:清理 DNS
错误说域名已有 DNS 记录。我去 Dashboard 看了看,确实有之前手动加的 AAAA 记录。
操作:
- 在 Cloudflare Dashboard → DNS → 记录
- 删除所有现有记录(保留 NS)
- 让 wrangler 重新创建
第 6 步:第二次 wrangler deploy
$ wrangler deploy
Uploaded <your-worker-name> (7.92 sec)
这次成功了!
Cloudflare 自动创建了:
- ✅ A 记录(指向 Cloudflare 代理 IP)
- ✅ AAAA 记录(指向 Cloudflare 代理 IP)
- ✅ SSL 证书
第 7 步:测试访问
https://<your-domain>/
页面加载出来了!
✅ 网盘登录页
✅ Basic Auth 验证通过
✅ 文件列表显示
✅ 上传功能正常
✅ 下载功能正常
第六章:那个诡异的 CNAME 错误
期间的小插曲
在清理 DNS 的过程中,我试图手动加一条 A 记录:
类型: A
名称: @
内容: 192.0.2.1(RFC 5737 测试 IP,不会真的访问到)
代理: 已代理
报错:
A CNAME record with that host already exists.
我懵了
我明明没创建 CNAME 啊?
用 dig 查了:
$ dig <your-domain> CNAME
# 什么都没有
但 Cloudflare Dashboard 说有 CNAME。
真相:CNAME Flattening
Cloudflare 有个特殊机制叫 CNAME Flattening:
- 允许在根域名(
@)放 CNAME 记录 - 在 DNS 解析时自动展开为 A 记录
- 外部 dig 看不到(flatten 了)
- Cloudflare 内部仍按 CNAME 追踪
这个隐藏的 CNAME 来自我之前的 wrangler deploy 失败:
- ✅ Worker 代码上传成功
- ⚠️ Custom Domain 部分成功(CNAME 已写入)
- ❌ A/AAAA 记录被冲突阻止
解决方法
- 在 Dashboard → DNS → 记录
- 找到隐藏的 CNAME(即使 dig 看不到)
- 删除它
- 重新 wrangler deploy
教训:
"看不到的 CNAME,不代表不存在。" "Cloudflare Dashboard 永远是最权威的 DNS 状态。"
第七章:国内访问测试
关键验证
部署成功后,最重要的一步:国内能否访问?
我用家里的宽带测试:
浏览器输入 https://<your-domain>/
加载中...
加载中...
✅ 网盘登录页!
能访问!
我又用手机 4G 测试:
✅ 能访问!
我让朋友从国内不同网络测试:
- ✅ 电信宽带:能访问
- ✅ 移动 4G:能访问
- ✅ 联通宽带:能访问
全部能访问!
验证成功
对比表:
| 域名类型 | 国内访问 | 原因 |
|---------|---------|------|
| *.workers.dev 子域 | ❌ Connection reset | GFW 精准干扰 workers.dev |
| <your-domain> 自定义域名 | ✅ 正常访问 | Cloudflare 代理 IP 不在 GFW 黑名单 |
金句:
"昨天死在网络上,今天活过来了。"
第八章:技术栈全景
最终的技术栈是这样的:
┌─────────────────────────────────────────────────┐
│ 用户设备(任意) │
└──────────────────────┬──────────────────────────┘
│ HTTPS 请求
↓
┌─────────────────────────────────────────────────┐
│ Cloudflare Edge Network │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ <your-domain> 域名 │ │
│ │ DNS: A + AAAA → Cloudflare 代理 IP │ │
│ │ (这些 IP 不在 GFW 黑名单) │ │
│ └──────────────┬──────────────────────┘ │
│ │ │
│ ↓ │
│ ┌─────────────────────────────────────┐ │
│ │ Worker: <your-worker-name> │ │
│ │ ├─ Basic Auth: admin/<password> │ │
│ │ └─ R2 Binding: <your-binding> │ │
│ └──────────────┬──────────────────────┘ │
│ │ │
└──────────────────┼────────────────────────────────┘
↓
┌───────────────────────────┐
│ Cloudflare R2 Bucket │
│ Name: <your-bucket> │
└───────────────────────────┘
关键点
- 域名指向 Cloudflare CDN(不是
workers.dev子域) - Cloudflare CDN 的 IP 段 在国内可以访问
- Worker 跑在 Cloudflare 边缘(不限速、不限额)
- R2 作为存储(10GB 免费,零流量费)
第九章:六个坑总结
整个过程我踩了 6 个坑:
坑 1:DNS 只有 AAAA,没有 A
问题:国内 IPv4 用户访问不到
根因:之前只配了 AAAA 记录(IPv6)
教训:国内部署必须配 A 记录(IPv4)
坑 2:Custom Domain 冲突已有 DNS
问题:错误码 100117,Custom Domain 添加失败
根因:域名已有 DNS 记录,Cloudflare 要求"干净"
教训:先用 wrangler 创建 Custom Domain,先不要手动配 DNS
坑 3:CNAME Flattening 隐藏陷阱
问题:添加 A 记录报 CNAME 冲突,但 dig 看不到 CNAME
根因:CNAME Flattening 机制,外部看不到,Dashboard 可见
教训:Cloudflare Dashboard 是权威
坑 4:Token 权限分层
问题:DNS API 调用失败
根因:Token 只有 Account 权限,缺 Zone 权限
教训:Account 级别 ≠ Zone 级别
坑 5:wrangler 部署半成品状态
问题:wrangler 报错,但 Worker 已经上传
根因:失败时部分资源已创建
教训:失败重试前,先清理残留状态
坑 6:部署目录选择错误
问题:wrangler 找不到 assets
根因:从外层目录部署
教训:找到真正可部署的根目录
第十章:后期维护
部署成功只是开始,维护才是长期工程。
1. 定期检查 Worker 状态
# 查看 Worker 列表
curl "https://api.cloudflare.com/client/v4/accounts/<your-account-id>/workers/scripts" \
-H "Authorization: Bearer <your-token>"
# 实时日志(需要登录)
wrangler tail
⚠️ API 调用时不要在公开场合贴出真实的 Account ID 和 Token。本地使用即可。
2. 定期检查 DNS
dig <your-domain> A +short
dig <your-domain> AAAA +short
如果 IP 变了,可能是 Cloudflare 调整了。
3. 定期轮换密码
每 3-6 个月换一次密码:
# 修改 src/index.ts
# password: "<new-strong-password>"
wrangler deploy
4. 备份 wrangler.toml
这是部署的核心配置,必须备份到 Git 或密码管理器。
5. 监控 R2 用量
R2 免费额度 10GB。在 Dashboard → R2 → Bucket → Metrics 查看。
6. 升级网盘 UI 库
cd <your-project-folder>/<deploy-root>
npm update <your-ui-package-name>
wrangler deploy
7. 灾备方案
万一账号被封:
备份清单:
- wrangler.toml
- src/index.ts
- R2 Bucket 内的文件(定期下载到本地)
恢复:
- 重新创建 Worker
- 重新上传文件
8. 安全审计清单
每季度检查一次:
- [ ] Worker 密码强度
- [ ] Token 是否轮换
- [ ] R2 Bucket 访问权限
- [ ] DNS 记录是否被篡改
- [ ] SSL 证书状态
第十一章:核心思路回顾
整个解决过程的核心思路
问题: 国内访问 Cloudflare Worker
↓
诊断: GFW 屏蔽的是什么?
↓
发现: workers.dev 子域被墙,Cloudflare CDN 本身没事
↓
思路: 用自己的域名代替 workers.dev
↓
方案: Cloudflare Custom Domains 自动管理 DNS
↓
实施: wrangler.toml + wrangler deploy
↓
验证: 国内访问测试
↓
结论: ✅ 国内可访问!
关键洞察
GFW 屏蔽的是"路径",不是"平台"。
- ❌ 屏蔽
*.workers.dev - ✅ 但 Cloudflare CDN 的 IP 段可以用
- ✅ 只要入口域名不在黑名单,就能绕过
给同样困境的人
如果你也有 Cloudflare Worker 国内访问不了的问题:
- 先诊断:GFW 屏蔽的是域名还是 IP?
- 找思路:能不能用别的入口?
- 用 Cloudflare Custom Domains:最省心
- 验证:多网络、多设备测试
第十二章:金句合集
整个过程我写了一些自认为有道理的话:
"问题不在物理层,而在配置层。"
"GFW 屏蔽的是路径,不是平台。"
"昨天死在网络上,今天活过来了。"
"Routes 不创建 DNS,Custom Domains 才创建 DNS。"
"看不到的 CNAME,不代表不存在。"
"wrangler 失败时,会有半成品状态残留。"
"国内部署:A 记录不是可选,是必须。"
"写文章时记得模糊化地址信息,避免被 GFW 溯源。"
第十三章:下一步
部署成功后,我计划做这些事:
- [ ] 把密码从源码移到 wrangler secret(避免 git 泄露)
- [ ] 启用 Cloudflare Access 做第二层保护
- [ ] 升级到更高级的网盘 UI(具体名字就不说了)
- [ ] 写一篇关于密码管理的博客
- [ ] 监控 Worker 流量和性能
结语
写完这篇文章,我有一种奇怪的感觉:
问题解开了,反而没什么戏剧性了。
没有那种"灵光一现"的顿悟时刻, 也没有那种"终于找到答案"的狂喜。
只是:
- 一步一步诊断
- 一个一个坑踩
- 一条一条命令敲
- 一遍一遍测试
然后,问题就解决了。
也许这就是技术的本来面目:
不是灵光一现,是日拱一卒。 不是顿悟,是积累到一定程度后的水到渠成。
如果你也在类似的问题里挣扎,希望这篇文章能给你一些思路。
GFW 不是不可逾越的墙,它是规则。 规则可以被理解,理解后就可以被绕过。
这大概就是技术人面对限制时,最朴素的信念。
⚠️ 最后提醒:本文所有地址、域名、Worker 名、目录名都用占位符代替。这不是偷懒,是保护自己。
想想看:如果你写一篇文章,把自己的 Cloudflare 自定义域名公布出来,GFW 维护者看到后,只要在
workers.dev黑名单旁边再加一个域名,你的服务就挂了。沉默是金。分享思路,保留细节。
写于 2026 年 6 月 22 日深夜 从"死在了网络上"到"活过来了" 🚀 保持沉默,安全第一 🔒
📎 附录:完整配置文件(已脱敏)
wrangler.toml
name = "<your-worker-name>"
compatibility_date = "<your-compatibility-date>"
main = "src/index.ts"
assets = {
directory = "<path-to-ui-dashboard>",
binding = "ASSETS",
html_handling = "auto-trailing-slash",
not_found_handling = "single-page-application"
}
[[r2_buckets]]
binding = "<your-r2-binding-name>"
bucket_name = "<your-bucket-name>"
[[routes]]
pattern = "<your-domain>"
custom_domain = true
zone_name = "<your-domain>"
[observability]
enabled = true
src/index.ts
import { <your-ui-library> } from "<your-ui-package-name>";
export default <your-ui-library>({
readonly: false,
basicAuth: {
username: "<your-username>",
password: "<your-strong-password>",
},
});
部署命令
cd <your-project-folder>/template
export PATH=/Users/zhangfengrun/nodejs/bin:$PATH
export CLOUDFLARE_API_TOKEN="<your-token>"
export CLOUDFLARE_ACCOUNT_ID="<your-account-id>"
wrangler deploy
占位符对照表
| 占位符 | 替换为 |
|--------|--------|
| <your-domain> | 你的自定义域名 |
| <your-worker-name> | 你的 Worker 名称 |
| <your-account> | 你的 Cloudflare 账户子域 |
| <your-account-id> | 你的 Cloudflare Account ID |
| <your-token> | 你的 Cloudflare API Token |
| <your-bucket-name> | 你的 R2 Bucket 名称 |
| <your-r2-binding-name> | wrangler.toml 里的 R2 binding 名 |
| <your-project-folder> | 你的部署项目文件夹 |
| <deploy-root> | 你的部署根目录(包含 wrangler.toml 的目录)|
| <path-to-ui-dashboard> | 你的网盘 UI 库的 dashboard 路径 |
| <your-ui-library> | 你使用的网盘 UI 库的主函数 |
| <your-ui-package-name> | 你使用的网盘 UI 库的 npm 包名 |
| <your-username> | 你的访问用户名(不一定非是 admin)|
| <your-strong-password> | 你的 Worker 访问密码(建议 11+ 字符,含特殊字符)|
| <your-compatibility-date> | 你的 wrangler 兼容性日期 |
| <latest-version> | wrangler 最新版本号 |