banner
约 2,700 字
9 分钟

零成本!用 CF 搭建基于 TG 的无限容量私有图床加网盘

摘要

K-Vault 是一款部署在 Cloudflare 上、利用 Telegram 无限存储空间的私有图床与网盘方案,完全免费、支持多存储后端(TG、R2、S3、Discord、HuggingFace、WebDAV、GitHub)。支持图片/视频/文档在线预览、分片上传、访客上传、API Token 认证、Telegram Webhook 直链回链等。本文介绍 Fork 部署、配置 TG 凭据与 KV、绑定域名,以及进阶的增强模式配置。

前言

最近的一个项目叫 K-Vault,一款部署在 Cloudflare 上、利用 Telegram 的无限存储空间的私人存储与图床方案。类似的方案其实还挺多的,比如 Telegraph-ImageTGIMGHub 等等,推荐这个项目的原因一是比较新,作者更新积极,二是功能比较多,除了 TG 还集成很多其他方案。只要不传一些奇怪的东西,TG 就足够用了。 项目地址https://github.com/katelya77/K-Vault

blog image

它和同类方案的定位差别

前面这句话可能有点绕,先说清楚:同样是"Cloudflare + Telegram 图床",这个项目的价值不在"能存图",而在"能存到多处、并且长期用得起"

同类轻量方案(比如 Telegraph-Image 那套)走的是极简路线:图片只存 Telegram,代码少、部署快。K-Vault 的定位不一样,它解决的是另两个问题:

第一,鸡蛋不放在一个篮子里。 它同时支持 Telegram、Cloudflare R2、S3 兼容存储、Discord、HuggingFace、WebDAV、GitHub 七种后端。这不是为了炫技——图床最怕的就是存储后端失效(Telegram 改接口、免费服务关停)。多后端意味着后端出事时你能把新图切到别处去,而不用重建整个图床。

第二,Cloudflare 的免费额度其实很紧,得省着用。 这是大多数教程不会细讲、但实际用几个月就会撞上的问题:Cloudflare 的 Workers KV 每天只有 1000 次写入额度。如果每上传一张图都写几次 KV,一天传几十张图就可能把整个账号的 KV 写额度耗光——影响的还可能是你账号下其他同样用 KV 的项目。

K-Vault 给出的解法是"签名直链 + 低 KV 写入模式",后面会展开讲原理。这是我认为它比同类项目值得用的核心理由。

功能特性

  • 无限存储 - 不限数量的图片和文件上传

  • 完全免费 - 托管于 Cloudflare,免费额度内零成本

  • 免费域名 - 使用 *.pages.dev 二级域名,也支持自定义域名

  • 多存储后端 - 支持 Telegram、Cloudflare R2、S3 兼容存储、Discord、HuggingFace、WebDAV、GitHub

  • Telegram Webhook 回链 - 机器人在频道/群接收文件后自动回复直链

  • KV 写入优化 - Telegram 可启用签名直链,显著降低 KV 读写消耗

  • 内容审核 - 可选的图片审核 API,自动屏蔽不良内容

  • 多格式支持 - 图片、视频、音频、文档、压缩包等

  • 在线预览 - 支持图片、视频、音频、文档(pdf、docx、txt)格式的预览

  • 分片上传 - 支持最大 100MB 文件(配合 R2/S3)

  • 访客上传 - 可选的访客上传功能,支持文件大小和每日次数限制

  • API Token 认证 - 支持 curl / ShareX / 脚本等程序化上传与调用

  • 多种视图 - 网格、列表、瀑布流多种管理界面

  • 存储分类 - 直观区分不同存储后端的文件

  • 双模部署 - 保留 Cloudflare Pages 部署,同时新增 Docker 自托管(docker compose up -d

  • 动态存储配置管理 - 支持在管理端通过 API 对存储配置进行新增/编辑/删除/测试/设为默认

  • 可插拔设置存储(Docker) - 基础站点设置可使用 sqlite(默认)或 Redis 协议后端(Upstash / Redis / KVrocks)

  • 前端路径简化 - 以根路径页面为主流程(//admin.html/webdav.html

  • GitHub Actions 镜像构建 - 主分支/Tag 自动构建并推送 api + web 镜像

先说清楚"签名直链"是怎么回事

这是整个项目最值得理解的一个设计,也是它和同类方案真正拉开差距的地方。

普通直链的问题:你访问 img.example.com/file/abc123,服务端得先查一次数据库或 KV——"abc123 对应哪个文件?"——查到了才知道去 Telegram 取哪张图。每访问一次图片就查一次 KV。Cloudflare KV 每天 10 万次读看着够用,但如果图片被大量外链、或者文章访问量上来,读额度消耗得很快。

签名直链的做法:链接里直接带上加密签名的文件信息,形如 img.example.com/file/abc123?sign=xxxxx。服务端拿到链接后,用密钥验证签名是否有效——有效就直接知道该取哪张图,完全不用查 KV。签名的作用是防止别人伪造文件 ID 来乱取图。

省下来的不只是 KV 读,更关键的是写入:开启签名直链后,系统不需要为每张图都建立"索引记录",KV 写入量随之大幅下降。项目里的 MINIMIZE_KV_WRITES 环境变量就是这个思路的开关——设为 true 时会一并启用签名直链

代价是什么? 签名直链的链接带上了一串签名参数,链接变长了,而且签名是绑定密钥的:换密钥等于全站链接失效。所以 FILE_URL_SECRET 一旦设好就别乱改,要么就别自己指定、让它回退用 Bot Token(这样至少不会因为改密钥而全站断链)。

准备部署

  1. 前置要求

  • Cloudflare账户

  • Telegram 账户(如使用 Telegram 存储)

  • Docker + Docker Compose(可选,用于自托管部署)

  1. 获取 Telegram 凭据

  • @BotFather 发送 /newbot

  • 按提示创建机器人,获得 BOT_TOKEN

blog image
  1. 创建频道并添加机器人

  • 创建一个新的 Telegram 频道

  • 将机器人添加为频道管理员

blog image
  1. 获取 Chat ID

blog image

这几步和同类项目完全一样,原理也一样:机器人必须被提升为频道管理员才有发布权限,否则上传时会被 Telegram 直接拒绝;频道 ID 是带负号的数字,填的时候别漏。建议为图床单独建一个机器人、单独建一个私有频道,别和别的用途混在一起——将来要轮换 Token 或清空数据时互不影响。

部署到 Cloudflare

  1. Fork 本仓库

  2. 创建 Pages 项目

  • 登录 Cloudflare Dashboard

  • 进入 Workers 和 Pages创建应用程序Pages连接到 Git

  • 选择 Fork 的仓库,点击部署

blog image
  1. 配置环境变量

  • 进入项目 设置环境变量

  • 添加必需变量:

变量名

说明

必需

TG_Bot_Token

Telegram Bot Token

TG_Chat_ID

Telegram 频道 ID

BASIC_USER

管理后台用户名

可选

BASIC_PASS

管理后台密码

可选

重新部署 - 修改环境变量后需重新部署生效

blog image

BASIC_USER / BASIC_PASS 标着"可选"——但从"图床管理后台"这个用途来说,它是必需的。不设的话,任何人只要猜到你的域名,就能打开后台浏览、上传、删除你的全部文件。这种"默认不设密码"的设计在很多自托管项目里都有,安全责任在部署者这边,别跳过

配置 KV 存储(图片管理,必需)

启用图片管理功能需要配置 KV:

  1. 进入 Cloudflare Dashboard → Workers 和 PagesKV

  2. 点击 创建命名空间,命名为 k-vault

blog image
  1. 进入 Pages 项目 → 设置函数KV 命名空间绑定

blog image
  1. 添加绑定:变量名 img_url,选择创建的命名空间

blog image
  1. 添加自定义域名

blog image
  1. 重新部署项目

绑定变量名必须是 img_url,这个不是随便起的——代码里按这个名字去取 KV 句柄,写错就是"后台看不到任何已上传的图"。另外注意顺序:先绑定、后重新部署,否则绑定不会生效。

如何使用

  1. 初次访问输入账户密码

blog image
  1. TG 频道添加机器人为管理员

blog image
  1. 查看连接状态

blog image
  1. 上传一个图片测试一下

blog image
  1. TG频道里也可以看到了

blog image

第 3 步的"连接状态"是很实用的一步——它相当于一个自检:能连上说明 Token、Chat ID、机器人权限三件事都对了。上传失败时先看这里,比盲猜快得多。第 5 步则验证了整套链路:文件确实进入了你的 Telegram 频道,你的数据是你的

多存储后端怎么选

项目支持七种后端,但日常真正会用的其实就这几个,取舍关系如下:

后端

适合什么

优势

局限

Telegram

图片、博客配图

无限容量、完全免费

单文件受 Bot API 限制

Cloudflare R2

需要稳定长期存放的文件

出网流量免费、S3 兼容、可挂自定义域名

免费额度 10GB

S3 兼容

已有对象存储(如其他厂商)

灵活、可对接已有资源

需自行承担费用/配置

WebDAV

已有 NAS / 网盘

数据落在自己手里

依赖你的网络与设备在线

GitHub

少量小文件

免费、有版本历史

仓库体积有限,不适合放图

Discord / HuggingFace

备用通道

免费额度可观

依赖第三方服务可用性

我的建议:日常博客配图走 Telegram(省心、无限);需要长期稳定、不希望依赖 TG 的正式素材走 R2(可控、出网免费);本地已经有 NAS 的话,WebDAV 是很好的兜底——因为数据真正落在你自己的机器上

Telegram 增强模式(自部署 Bot API + Webhook)

项目已支持将 Telegram API 基础地址切换为自部署 Bot API,并支持通过 Webhook 在群/频道接收文件后自动回复直链。官方 Bot API 会有单文件 20 兆限制,自部署的话是 20G 的限制。

关键环境变量:

变量名

说明

示例

CUSTOM_BOT_API_URL

自部署 Bot API 地址(不填则默认 https://api.telegram.org

http://127.0.0.1:8081

PUBLIC_BASE_URL

Webhook 回链时使用的公网域名(建议填写)

https://img.example.com

TG_WEBHOOK_SECRET

Webhook 密钥,校验头 X-Telegram-Bot-Api-Secret-Token

your-secret

TELEGRAM_LINK_MODE

Telegram 链接模式,设为 signed 启用签名直链

signed

MINIMIZE_KV_WRITES

设为 true 时启用低 KV 写入策略(也会启用签名直链)

true

TELEGRAM_METADATA_MODE

Telegram 元数据写入策略:off 关闭后台索引写入,默认写轻量索引

off

TG_UPLOAD_NOTIFY

网页上传成功后,是否额外发送"直链+File ID"通知消息

true

FILE_URL_SECRET

签名直链密钥(不填则回退到 TG_Bot_Token

random-long-secret

这几个变量的取舍,说到底就是"省额度"和"后台可管理"二选一。

  • 想要后台能看到每张图的记录(能搜索、能按存储分类浏览)→ 保留默认的元数据写入,但 KV 写入会变多

  • 想把 Cloudflare 免费额度压到最低、链接也尽量短 → 用 TELEGRAM_LINK_MODE=signed + MINIMIZE_KV_WRITES=true,代价是后台的索引信息会少一些

TG_WEBHOOK_SECRET 建议一定要设——Webhook 接口是公网可访问的,谁都能往上打请求。加了这个密钥后,只有携带正确 X-Telegram-Bot-Api-Secret-Token 头的请求才会被处理,否则等于给陌生人开了个"往你频道里塞东西"的入口。

Webhook 部署步骤:

  1. 在 Telegram 中把 Bot 拉进目标频道/群并授予发言权限(频道建议管理员)。

  2. 在 Cloudflare Pages 中配置 TG_Bot_TokenPUBLIC_BASE_URLTG_WEBHOOK_SECRET,然后重新部署。

blog image

blog image
  1. 重新部署生效 4. 调用 setWebhook 指向本项目接口: 测试: 新开页面打开以下连接注意不要有空格 https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook?url=【你的url】/api/telegram/webhook&secret_token=【你的SECRET】

blog image
  1. 测试一下:频道/群内发送图片或文件,Bot 会自动回复 /file/... 直链。

blog image
  1. 管理后台也可以看到并预览

blog image

第 4 步"注意不要有空格"这句提醒不是多余的,这是最容易踩的坑:把 URL 粘进浏览器时,前后带了空格或者换行,Telegram 接口会返回 Bad Request 或干脆不生效,但错误信息不会直接告诉你"是空格的问题"。建议用脚本或一行命令调用,避免手工拼接出错:

bash
curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook?url=https://img.example.com/api/telegram/webhook&secret_token=<YOUR_SECRET>"

返回 {"ok":true,...} 才算设置成功。

然后还可以根据官方文档,添加一些其他的环境变量,或添加其他存储桶。

使用限制

Cloudflare 免费额度:

  • 每日 100,000 次请求

  • KV 每日 1,000 次写入、100,000 次读取、1,000 次列出

  • 超出后需升级付费计划($5/月起)

  • 建议 Telegram 场景开启签名直链或低 KV 写入模式以降低额度压力

blog image
  • Docker 自托管模式下,Node 运行时不受 Cloudflare 免费额度限制(受你自己的服务器和存储后端限制)

把 KV 的写入额度换算成"能传多少张图",你就有概念了:每天 1000 次写入,如果开默认模式、一张图消耗 1-2 次写入,那就是每天几百张的上限——个人用完全够;但这个额度是整个 Cloudflare 账号共享的,同一账号下如果还跑着短链、评论、监控等其他用 KV 的项目,它们会一起抢这 1000 次。所以前面推荐的签名直链 + 低 KV 写入模式,实际是在保护你账号里所有项目的余量。

请求数再高的 CF 就无法满足了,可以在境外 VPS 用 Docker 部署。有兴趣的可以自己尝试,本文就不再继续演示了。

常见问题

Q:上传成功,但管理后台看不到图片?

先查 KV 绑定:变量名必须是 img_url,绑定后必须重新部署。其次看你是否开了 MINIMIZE_KV_WRITES 或把 TELEGRAM_METADATA_MODE 设成了 off——这两个都会减少后台索引信息,属于有意的取舍,不是故障。

Q:图片能上传但访问链接 404?

大概率是 PUBLIC_BASE_URL 没填或填错(结尾多了斜杠也是常见问题,应该是 https://img.example.com,不带最后那个 /)。另外如果用签名直链,FILE_URL_SECRET 中途改过的话,之前生成的老链接会全部失效

Q:能不能完全不用 Cloudflare,只跑 Docker?

可以。项目支持 Docker 自托管,运行时不再受 Cloudflare 免费额度约束,受你自己服务器和存储后端的限制。适合图片量大、或者不想把数据链路经过第三方的情况,代价是要自己维护服务器、证书和备份。

Q:我该选它还是选更简单的方案?

一句话判断:只想放博客配图、图不多 → 用极简方案(如 Telegraph-Image),十分钟搞定;要当私人网盘用、文件类型多、需要多后端兜底、在意 Cloudflare 额度 → 用 K-Vault。 两者部署难度差别不大,主要差在配置项的多少和后续的灵活性。

⚠️ 最后一条安全提醒,适用于所有"TG 图床"方案:你的 Bot Token 就是图床的钥匙,泄露等于别人能往你的存储频道里写东西。别把 .env、带 Token 的截图或后台配置页发到公开场合;万一泄露了,去 BotFather 用 /revoke 换一个 Token——换完记得同步更新 Cloudflare 上的环境变量并重新部署。

END