出海建站实战:用Cloudflare自建视频 CDN,月省千元还能防盗
封面图
如果你在做付费课程、会员内容、或者任何需要视频的出海产品,应该有体悟,视频平台要么贵、要么不可控。
Vimeo 最便宜的 Starter 也要 $12/月,想要高级隐私控制得升到 Advanced $75/月。Wistia 更贵。
我们最近在做出海社区,涉及到视频课程,最开始 AI 推荐了 YouTube,操作最简单,把视频上传到 YouTube,把视频链接嵌入到网站。但是这样有个问题,不好做权限控制。
最后评估了几种方式,最终采取了一套自建方案,基本零成本,而且视频只有付费用户能看。防盗链、断点续播、拖进度条流畅,全都有。
Cloudflare R2 存储定价:前 10GB 免费,超出 $0.015/GB/月。比如一门课 20 个视频,每个 500MB,总共 10GB,月费 $0。
流量费?R2 出站流量不收费。这也是当初 Cloudflare 推 R2 最大的卖点,做视频这种吃流量的场景,省的钱非常可观。
架构长这样
javascript用户浏览器 ↓ 请求 /api/videos/intro/token Next.js 后端 ↓ 验证付费状态,生成签名 URL(有效期 2 小时) Cloudflare Worker(videos.chuhai.fyyd.net) ↓ 验证签名,读取视频 Cloudflare R2(视频文件存储)
简单说就三个角色。R2 负责存视频文件,不对外直接暴露。Worker 是鉴权网关,验证请求合法才放行。Next.js 后端签发临时 token,跟用户的付费状态绑定。
架构流程图
防盗链怎么实现
核心是 HMAC-SHA256 签名。用户每次请求视频,后端生成一个带过期时间的签名 token:
javascripthttps://videos.example.com/course-01.mp4 ?token=a3f9...(HMAC 签名) &expires=1741234567890(2小时后过期)
Worker 收到请求后,用同一个密钥重新算一遍签名,对不上就 403。过了过期时间也 403。
所以把链接发给别人,2 小时后就失效了。不是付费用户,后端根本不给签 token。要是想更严格,还可以把链接和 IP 绑定,我们没加,目前够用了。
视频卡顿问题
最开始视频播放很卡,播放几秒就要加载一下,体验感不好。
让大模型深度分析了一下原因,80% 的原因是重复回源。
用户拖到 5 分钟的位置,浏览器发一个 Range 请求(Range: bytes=xxx-yyy),如果服务器没缓存,就得从存储重新读一遍。
解决方法是 Worker 做了两层缓存。
第一层是浏览器缓存,已经下载过的片段浏览器直接用本地缓存,不再发请求。
第二层是 Cloudflare 边缘缓存。第一个用户看完视频的时候,Worker 把数据流一分为二:一路实时返回给用户,另一路写进 Cloudflare 边缘节点缓存。
第二个用户请求同一个视频,直接从最近的边缘节点返回,不回源 R2。
当然这上面说的细节你并不需要知道。交给大模型解决。
有个细节值得说一下:缓存 key 只含路径,不含 token。这样不同用户请求同一个视频,共享同一份缓存,不会每人缓存一份。
从零搭建:完整操作流程
整个流程分两部分:先在 Cloudflare 控制台手动配置一次,之后代码更新全靠 Wrangler 命令行,不用再进网站。
第一部分:Cloudflare 控制台操作
Step 1:创建 R2 Bucket
Cloudflare Dashboard → R2 → 创建 Bucket,命名随意。不要开启公开访问,视频只走 Worker。
创建 R2 Bucket
Step 2:创建 Worker
Cloudflare Dashboard → Workers & Pages → 创建 Worker,起个名字,比如 my-video-cdn。代码先随便填,后面用 Wrangler 覆盖。
创建 Worker 入口
创建 Worker 详情
Step 3:给 Worker 绑定 R2
进入 Worker → Settings → Bindings → 添加 R2 Bucket 绑定。
变量名填 R2_BUCKET,选刚才创建的 bucket。这样 Worker 代码里就能用 env.R2_BUCKET.get(key) 直接读文件。
绑定 R2 Bucket
Step 4:绑定自定义域名(可选)
Worker 部署完成后默认有一个 *.workers.dev 的地址,比如 my-video-cdn.yourname.workers.dev,直接用这个完全没问题。
如果想用自己的域名(比如 videos.yourdomain.com),进入 Worker → Settings → Domains → 添加自定义域。前提是这个域名已经托管在 Cloudflare DNS 上。不需要的话跳过这步即可。
Step 5:设置密钥
有两种方式,选一个就行:
方式一:Cloudflare 控制台(更直观)
Worker → Settings → Variables and Secrets → 添加 Secret,名称填 VIDEO_SECRET,值填一串随机字符串。
设置密钥
方式二:Wrangler 命令行
bashnpx wrangler secret put VIDEO_SECRET # 输入密钥值后回车
同样的密钥也要填到你的后端项目里(比如 Vercel 的环境变量 VIDEO_SECRET),两端用同一个密钥做签名和验证。
第二部分:视频处理与上传
R2 不带自动转码,视频要提前编码好再上传。推荐免费工具 HandBrake(handbrake.fr),一般 60 分钟视频压缩后在 500MB - 1GB 之间。
上传直接在 R2 控制台拖进去就行,文件名就是后续 Worker 取文件用的 key,起名简单清晰就够了。
第三部分:用 Wrangler 部署 Worker 代码
Wrangler 是 Cloudflare 官方的命令行工具。
有了它,不用每次改代码都登录 Cloudflare 网站手动粘贴,直接在终端跑一行命令,十秒内全球生效。
Worker 代码也可以像普通项目一样提交 Git 做版本管理。
bash# 首次登录 Cloudflare(只需一次,会弹出浏览器授权) npx wrangler login # 部署 Worker 代码 npx wrangler deploy
Wrangler 登录授权
Wrangler 部署过程
Wrangler 部署成功
改了 Worker 代码之后只需跑 wrangler deploy,十秒内全球生效。Worker 代码可以提交到 Git 做版本管理,和普通项目代码一样维护。
什么场景合适
最匹配的是付费课程平台,视频是核心资产,防盗是刚需。会员内容站、内部培训视频也很适合。海外用户为主的话更好,Cloudflare 全球 300 多个节点,不管用户在哪都快。
另外这套方案不带转码,视频得自己提前编码好再上传,不像 Vimeo 和 Wistia 会自动帮你转。
对出海独立开发者来说,R2 + Worker 是目前性价比很高的视频自托管方案。存储几乎免费、流量不收钱、鉴权完全自控、一行命令部署。