面向 Cloudflare R2 的轻量级、自托管文件管理器。FlareDrive 使用 React 与 Vite 提供 Web 文件管理界面,通过 Cloudflare Pages Functions 暴露 WebDAV API,并将文件存储在 R2 中;需要网页登录时,可选用 D1 保存会话。
Cloudflare 免费额度包含 10 GB R2 存储空间和每天 100,000 次 Pages Functions 调用。查看官方价格
简体中文 | English
- 网格和详细信息两种视图,支持按名称、修改时间、类型和大小排序或分组
- 搜索、面包屑导航以及与浏览器前进/后退同步的目录 URL Hash
- 桌面端框选、
Ctrl/Cmd多选、Shift范围选择和右键菜单 - 移动、复制、重命名、删除、批量下载和复制文件链接
- 文件夹递归复制、移动和删除,支持将文件直接拖入目标文件夹
- 上传单个或多个文件、整个文件夹,以及拖放文件或文件夹
- 移动设备支持拍照上传和选择图片或视频
- 大文件自动使用 R2 Multipart Upload;上传队列支持进度、取消和失败状态
- 图片、视频和 PDF 上传时生成内容哈希缩略图,并存入隐藏的内部命名空间
- 图片缩放查看,浏览器原生音频、视频和 PDF 查看
- 文本、Markdown 和 HTML 在线编辑、另存为及保存回 R2
- Markdown 提供预览、分栏和编辑模式;HTML 在 sandbox iframe 中预览
- ZIP 压缩包内容列表和单文件下载
- DOCX、PPTX、XLSX、XLS 和 CSV 在独立 sandbox iframe 中本地渲染
- Office 渲染器按格式延迟加载,打开一种格式不会加载另外两种格式的依赖
- 标准 WebDAV Basic Auth 管理员账号
- 可选的单账号密码登录、D1 Session 和“退出所有设备”
- 可选 Cloudflare Turnstile,只保护密码登录接口
- WebDAV 范围令牌,支持只读
ro、读写rw和仅上传up - 可选公开读取,仅开放
GET、HEAD和PROPFIND
文件管理与多选
Markdown 编辑与预览
ZIP 文件预览
flowchart LR
Browser["Web 应用<br/>React + Vite"]
WebDAV["/webdav/*<br/>Pages Functions"]
Auth["/api/auth/*<br/>Pages Functions"]
R2["R2 Bucket<br/>BUCKET"]
D1["D1 会话库<br/>AUTH_DB,可选"]
Office["Office 预览 iframe<br/>opaque origin"]
Browser -->|WebDAV 请求| WebDAV
WebDAV --> R2
Browser -->|密码登录| Auth
Auth --> D1
Browser -. "MessageChannel 传输 ArrayBuffer" .-> Office
主页面先通过已认证的 /webdav 请求下载 Office 文件,再使用一次性 MessageChannel 将 ArrayBuffer 传入 iframe。iframe 只包含 sandbox="allow-scripts",没有 allow-same-origin;sandbox 与 CSP 共同禁止网络请求、表单、弹窗、对象、子框架和顶层导航。
主要技术组件:
| 层级 | 实现 |
|---|---|
| Web 前端 | React 19、MUI 9、Vite 8、TypeScript |
| API | Cloudflare Pages Functions / Workers Runtime |
| 文件存储 | Cloudflare R2 |
| 登录会话 | Cloudflare D1,可选 |
| 文档预览 | Viewer.js、PDF.js、docx-preview、pptx-preview、SheetJS、Univer |
- Cloudflare 账号
- 一个 R2 存储桶
- 一个与 Cloudflare Pages 连接的 Git 仓库或 Wrangler CLI
将 fork 或克隆后的仓库连接到 Cloudflare Pages,并使用以下设置:
| 设置 | 值 |
|---|---|
| Framework preset | None |
| Build command | npm run build |
| Build output directory | build |
| Root directory | 仓库根目录 |
部署前至少配置 R2 绑定:
| 类型 | 绑定名称 | 是否必需 | 用途 |
|---|---|---|---|
| R2 Bucket | BUCKET |
是 | 存储文件和内部缩略图 |
| D1 Database | AUTH_DB |
仅 Password 模式 | 保存登录 Session 的哈希和过期时间 |
配置绑定和环境变量后重新部署。public/_routes.json 只将 /webdav/* 和 /api/auth/* 交给 Pages Functions,其他路径作为静态资源提供。
默认认证模式是 basic。设置:
FLAREDRIVE_AUTH_MODE="basic"
WEBDAV_USERNAME="admin"
WEBDAV_PASSWORD="replace-with-a-strong-password"首次访问 WebDAV 时,浏览器或 WebDAV 客户端会显示 HTTP Basic Auth 登录提示。
npm ci
npm run build
npx wrangler pages deploy build --project-name <your-pages-project>| 模式 | Web 应用 | WebDAV 客户端 | 主要配置 |
|---|---|---|---|
basic |
依赖浏览器 HTTP Basic Auth | 管理员账号或范围令牌 | WEBDAV_USERNAME、WEBDAV_PASSWORD |
password |
登录对话框、D1 Session Cookie | 仍使用管理员 Basic Auth 或范围令牌 | AUTH_DB、FLAREDRIVE_LOGIN_ACCOUNT、FLAREDRIVE_LOGIN_PRIVATE_KEY |
| Public Read | 无认证读取列表和文件 | 无认证读取 | WEBDAV_PUBLIC_READ="1" |
Password 模式只提供一个网页登录账号。WebDAV 客户端继续使用 WEBDAV_USERNAME、WEBDAV_PASSWORD 或范围令牌。
- 创建 D1 数据库,并绑定为
AUTH_DB。 - 执行 Session Schema:
npx wrangler d1 execute <database-name> --remote --file migrations/0001_auth_sessions.sql- 生成密码的 SHA-256:
node -e "const crypto=require('crypto'); console.log(crypto.createHash('sha256').update(process.argv[1]).digest('hex'))" "replace-with-a-strong-password"- 生成 ECDH P-256 私钥:
node -e "const { webcrypto } = require('crypto'); (async () => { const pair = await webcrypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey']); console.log(JSON.stringify(await webcrypto.subtle.exportKey('jwk', pair.privateKey))); })()"- 配置以下变量:
FLAREDRIVE_AUTH_MODE="password"
FLAREDRIVE_LOGIN_ACCOUNT='{"username":"admin","password":"<sha256-hex>"}'
FLAREDRIVE_LOGIN_PRIVATE_KEY='<private-jwk-json>'网页登录载荷使用临时客户端 ECDH P-256 密钥协商 AES-GCM 密钥后加密。登录成功后,服务端设置不透明的 HttpOnly、SameSite=Lax Session Cookie;HTTPS 请求还会设置 Secure。D1 只保存 Session Token 的 SHA-256,不保存原始 Token。
同时配置以下两个值,Password 登录接口才会要求 Turnstile:
FLAREDRIVE_TURNSTILE_SITE_KEY="<turnstile-site-key>"
FLAREDRIVE_TURNSTILE_SECRET_KEY="<turnstile-secret-key>"Turnstile 不保护 WebDAV Basic Auth,也不会改变范围令牌行为。
先为每个原始 Token Secret 生成 SHA-256,然后将哈希写入 WEBDAV_ACCESS_TOKENS:
WEBDAV_ACCESS_TOKENS='[{"username":"phone","password":"<sha256-hex>","access":"rw","includes":["photos/phone/"],"excludes":["photos/phone/private/"]},{"username":"dropbox","password":"<sha256-hex>","access":"up","includes":["uploads/"],"excludes":[]}]'access |
允许的操作 |
|---|---|
ro |
GET、HEAD、PROPFIND |
rw |
所有受支持的 WebDAV 和分片上传操作 |
up |
文件 PUT、分片创建/上传/完成以及分片中止;不能读取、列目录、建目录、复制、移动或删除已有文件 |
includes 和 excludes 使用 R2 对象键路径,而不是完整 URL。范围允许路径本身和其子路径;例如 photos/phone 不会匹配 photos/phonebook。excludes 优先于 includes,COPY 和 MOVE 的目标也必须位于允许范围内。
WebDAV 客户端登录时输入 Token 的 username 和原始 Token Secret,不是配置中的 SHA-256。范围客户端应直接连接到其允许前缀,例如:
https://<your-domain>/webdav/photos/phone/
up Token 无法创建父目录,因此目标父目录必须已存在;直接上传到存储桶根目录时除外。
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
BUCKET |
R2 绑定 | 无 | 主文件存储,必需 |
AUTH_DB |
D1 绑定 | 无 | Password 模式 Session 数据库 |
FLAREDRIVE_AUTH_MODE |
变量 | basic |
basic 或 password |
WEBDAV_USERNAME |
Secret/变量 | 无 | WebDAV 管理员用户名 |
WEBDAV_PASSWORD |
Secret | 无 | WebDAV 管理员密码 |
WEBDAV_ACCESS_TOKENS |
Secret | 无 | 范围令牌 JSON 数组 |
WEBDAV_PUBLIC_READ |
变量 | 未启用 | 设置为 1 时公开 GET、HEAD、PROPFIND |
FLAREDRIVE_LOGIN_ACCOUNT |
Secret | 无 | 单账号用户名和密码哈希 JSON |
FLAREDRIVE_LOGIN_PRIVATE_KEY |
Secret | 无 | Password 登录使用的 ECDH P-256 私有 JWK |
FLAREDRIVE_TURNSTILE_SITE_KEY |
变量 | 无 | Turnstile 前端 Site Key |
FLAREDRIVE_TURNSTILE_SECRET_KEY |
Secret | 无 | Turnstile 服务端 Secret Key |
FLAREDRIVE_SESSION_TTL_SECONDS |
变量 | 86400 |
普通登录有效期 |
FLAREDRIVE_REMEMBER_TTL_SECONDS |
变量 | 604800 |
“保持登录”有效期 |
生产密钥应使用 Cloudflare Secret 或受保护的环境变量,不要写入 Git。
npm ci复制本地配置模板:
# Windows PowerShell
Copy-Item .dev.vars.example .dev.vars# macOS / Linux
cp .dev.vars.example .dev.vars编辑 .dev.vars。使用 Basic 模式时无需初始化 D1;使用 Password 模式时执行:
npx wrangler d1 execute AUTH_DB --local --config wrangler.local.jsonc --file migrations/0001_auth_sessions.sql启动前后端:
npm run dev| 服务 | 地址 | 说明 |
|---|---|---|
| Vite | http://127.0.0.1:3601 |
前端、HMR,并代理 /webdav 和 /api |
| Wrangler Pages Dev | http://127.0.0.1:3602 |
Pages Functions、Local R2 和 Local D1 |
打开 http://127.0.0.1:3601。Basic 模式下,前端不会把开发账号直接写入请求头;浏览器在 /webdav/ 返回认证挑战时要求输入凭据。
npm run build
npm run previewnpm run preview 在 http://127.0.0.1:3600 只预览已经构建的静态前端,不会启动 Pages Functions。
| 命令 | 作用 |
|---|---|
npm run dev |
同时启动 Vite 和本地 Pages Functions |
npm run dev:frontend |
只启动 Vite,端口 3601 |
npm run dev:functions |
只启动 Wrangler Pages Dev,端口 3602 |
npm run build |
TypeScript 类型检查并生成生产构建到 build/ |
npm run preview |
预览 build/ 中的静态前端 |
npm run lint |
检查 src/、functions/ 和构建配置 |
管理员端点:
https://<your-domain>/webdav/
支持的方法:OPTIONS、PROPFIND、MKCOL、HEAD、GET、POST、PUT、COPY、MOVE 和 DELETE。其中 POST 及带查询参数的部分 PUT/DELETE 用于 Web 应用的 R2 Multipart Upload 流程。
Web 应用对小于 100,000,000 字节的文件使用普通 PUT,达到该值时切换到自定义分片上传。普通 WebDAV 客户端通常只使用标准 PUT,不会自动使用 FlareDrive 的分片 API;上传大文件时建议使用 Web 应用。
Basic Auth 会在每次请求中发送 Base64 编码的账号密码。Base64 不是加密,请始终通过 HTTPS 使用生产站点。
| 类型 | 行为 | 浏览器内大小限制 |
|---|---|---|
| 图片 | Viewer.js 缩放查看 | 未设置专用限制 |
| 音频 / 视频 | 浏览器原生播放器 | 未设置专用限制 |
| 新窗口使用浏览器查看;PDF.js 用于生成缩略图 | 未设置专用限制 | |
| 文本 / Markdown / HTML | 预览、编辑、保存和另存为 | 2 MiB |
| ZIP | 文件列表和单文件下载 | 30 MiB |
| DOCX / PPTX / XLSX / XLS / CSV | sandbox iframe 内本地解析和渲染 | 小于 10 MiB |
Office 预览以兼容和快速浏览为目标,复杂字体、动画、宏、嵌入对象或高级公式不保证与桌面 Office 完全一致。项目不会执行 Office 宏。
- Office 和 HTML 预览运行在没有
allow-same-origin的 sandbox iframe 中;Office iframe 的 sandbox 与 CSP 禁止网络、表单、对象、嵌套 iframe、弹窗和顶层导航;DOCX 额外禁用altChunkHTML,并在渲染完成后移除链接和导航能力;Markdown 渲染则跳过原始 HTML - 上传或下载 HTML、SVG、XHTML 等活动内容时,WebDAV 强制附件响应、
nosniff和 sandbox CSP - 内部
_$flaredrive$/命名空间不会出现在普通目录列表,并限制为受控缩略图操作 - Password 模式只在 D1 存储 Session Token 哈希
- 范围令牌会校验源路径、
COPY/MOVE顶层目标及每个递归派生目标
本项目当前是单账号文件管理器,不包含多租户权限模型、操作审计日志或恶意文件扫描。
index.html Vite 主入口
office-preview.html 隔离的 Office iframe 入口
src/ React Web 应用
src/office-preview/ DOCX、PPTX、Spreadsheet iframe 运行时
functions/webdav/ WebDAV Pages Functions 和方法处理器
functions/api/auth/ Password Session API
functions/auth.ts 登录、Turnstile、Cookie 和 D1 Session 工具
migrations/ D1 Schema
public/_headers Office iframe CSP 和静态资源 CORS
public/_routes.json Pages Functions 路由范围
vite.config.ts Vite、代理、Worker 和预览分包配置
- Password 模式只支持一个配置账号,不是多用户网盘
- Public Read 会让任何访问者无需认证即可列出和读取允许的 WebDAV 内容
- 大目录的递归复制、移动和删除会产生多次 R2 操作
- 本项目基于 longern/FlareDrive 持续演进
- WebDAV 实现源自 abersheeran/r2-webdav


