在公有云服务商动辄涨价数据隐私无保障账号绑定难以迁移的今天,「数据自主」已经不再是技术极客的小众追求,而是普通用户保障数字资产安全的刚需。本文将带你从零搭建一款旗舰级私有云存储系统,基于 Next.js 构建前端界面,支持 MinIO(本地私有部署)和 Cloudflare R2(低成本对象存储)双后端,具备断点续播全盘搜索多账户无缝切换等核心功能,最后通过 Fly.io 完成轻量化部署(天然支持 IPv6,国内用户友好,预授权无实际扣费),真正实现数据 100% 可控,告别公有云绑架。
一为什么选择这套方案?
1. 核心痛点解决(告别公有云绑架)
- 🔒 数据自主:存储在自己的 MinIO 服务器或 R2 桶,无第三方数据泄露风险,不受服务商条款约束
- 💸 低成本:R2 无出口带宽费,MinIO 可部署在闲置设备上,Fly.io 免费额度满足个人使用
- 🚀 轻量化:无需复杂运维,Next.js 前端+Fly.io 部署,10 分钟完成上线
- �IPv6 原生支持:Fly.io 天然支持 IPv6,解决国内 IPv4 公网获取困难访问不稳定的问题
2. 项目核心亮点(旗舰级功能体验)
- 多账户无缝切换:支持 MinIO/R2 多账号配置,一键切换,管理多个存储桶
- 断点续播:视频播放进度自动保存,跨设备恢复观看,媲美商业云盘
- 全盘深度搜索:快速检索所有文件,支持文件名模糊匹配,无需逐层查找
- 拖拽批量上传:支持文件/文件夹拖拽上传剪贴板粘贴上传,支持上传进度显示
- 毛玻璃精美 UI:现代化视觉设计,兼顾美观与实用性
- 用量统计:R2 专属本月用量统计(存储/Class A/Class B 操作),精准校准
- 分享功能:支持临时签名链接(1 小时~7 天)和永久公开链接,灵活分享文件
- 批量操作:文件/文件夹的移动重命名删除,高效管理数据
3. 技术栈选型
- 前端框架:Next.js 16(App Router,React 19),服务端渲染+客户端交互兼顾
- 存储后端:MinIO(私有部署)/ Cloudflare R2(对象存储),S3 协议兼容
- 部署平台:Fly.io(IPv6 原生支持轻量预授权无实际扣费国内友好)
- 辅助工具:AWS SDK for S3(存储交互)Tailwind CSS(样式)react-hot-toast(消息提示)
二前期准备
1. 基础环境安装
- Node.js ≥ 20.x(推荐 LTS 版本,用于项目构建和依赖安装)
- Git(用于拉取项目代码)
- MinIO 环境(可选,私有部署存储,可部署在本地服务器NAS 设备)/ Cloudflare R2 账号(可选,低成本对象存储)
2. Fly.io CLI 安装(重点)
Fly.io 是一款轻量级容器部署平台,天然支持 IPv6,也是本文选择的部署载体,首先安装其 CLI 工具(对应你的操作命令):
步骤 1:执行安装脚本
# Linux/macOS 系统(本文演示,对应你的操作)
curl -L https://fly.io/install.sh | sh
步骤 2:加载环境变量
安装完成后,需要将 Fly.io CLI 加入系统环境变量,使其可以全局调用:
# 针对 bash 终端(你的终端环境)
source ~/.bashrc
# 若为 zsh 终端,执行:
# source ~/.zshrc
步骤 3:验证安装成功
执行以下命令,若能显示 Fly.io CLI 版本信息,说明安装成功:
fly version
三Fly.io 快速上手(第一次使用指南)
对于第一次使用 Fly.io 的用户,核心需要解决「登录」「绑定信用卡(预授权)」「验证 IPv6 支持」三个问题,其中预授权问题是国内用户最关心的。
1. Fly.io 账号登录
# 执行登录命令,会自动打开浏览器跳转至 Fly.io 官网登录页面
fly auth login
- 可使用 GitHub 账号快速登录,无需单独注册
- 登录成功后,终端会显示账号关联信息,完成 CLI 与账号的绑定
2. 绑定信用卡(预授权说明,国内用户友好)
Fly.io 作为海外平台,需要绑定信用卡完成身份验证,但仅会产生「小于 10 美元的预授权」,1 分钟内会自动退回,无实际消费,国内银联信用卡VisaMasterCard 均支持。
绑定步骤:
- 登录 Fly.io 官网后台(https://fly.io/dashboard)
- 点击左侧「Billing」(账单)选项,进入账单设置页面
- 点击「Add Payment Method」(添加支付方式),输入信用卡信息(卡号有效期CVV 码)
- 提交后,银行会收到「预授权扣款通知」(无实际资金转出,仅冻结部分额度)
- 等待 1-2 分钟,预授权额度会自动解冻,Fly.io 后台显示「Payment Method Verified」(支付方式已验证)
注意事项:
- 预授权金额通常为 5 美元或 10 美元,具体以银行通知为准
- 若绑定失败,可尝试更换信用卡(部分银行对海外预授权支持不佳)
- 验证完成后,可在 Fly.io 后台设置「Spend Limit」(消费限额)为 0 美元,彻底避免意外扣费
3. 验证 Fly.io IPv6 支持
Fly.io 所有应用均默认开启 IPv6 支持,无需额外配置,验证方式如下:
- 后续部署项目完成后,可通过
fly ips list命令查看应用的 IP 地址 - 其中标注「ipv6」的地址即为该应用的 IPv6 访问地址
- 也可通过在线 IPv6 检测工具,输入应用域名(
xxx.fly.dev),验证 IPv6 可达性
4. 绑定域名
- Fly.io 端:运行
fly certs create your-domain.com。 - Cloudflare 端:添加一条
CNAME记录,Name 填子域名,Target 填 xxxx.dev,并确保关闭代理(关闭小黄云)。 - 等待生效,然后通过您自己的域名访问。
- fly certs check '
your-domain.com' 查看域名进度yys@yys-defaultstring:~/r2-drive$ fly certs check 'cloud.yysresume.work' Status = Awaiting certificates Hostname = cloud.yysresume.work DNS Provider = cloudflare Certificate Authority = Let's Encrypt Issued = Added to App = 13 minutes ago Source = fly Your certificate for cloud.yysresume.work is being issued. Status is Awaiting certificates.
四项目搭建与核心配置
1. 拉取项目代码
# 克隆项目(本文基于你提供的 r2-drive 项目)
git clone https://github.com/xxx/r2-drive.git(替换为实际项目地址)
cd r2-drive
2. 安装项目依赖
npm install
# 若使用 yarn/pnpm,对应执行 yarn install / pnpm install
3. 核心配置解读(MinIO/R2 双支持)
项目的核心优势之一是兼容 MinIO(私有)和 R2(公有低成本),关键配置在 lib/s3.ts 中的 createS3Client 工具类,解决了 SSL 证书路径风格等兼容问题:
// lib/s3.ts
export const createS3Client = (config: R2Config) => {
if (!config || !config.endpoint) {
throw new Error("配置无效: Endpoint 缺失")
}
const requestHandler = new NodeHttpHandler({
httpAgent: new http.Agent({ keepAlive: true timeout: 60000 })
httpsAgent: new https.Agent({
keepAlive: true
rejectUnauthorized: false // 允许自签名证书,适配 MinIO 私有部署
timeout: 60000
})
})
return new S3Client({
region: "auto"
endpoint: config.endpoint
forcePathStyle: true // 兼容 MinIO 路径风格
requestHandler: requestHandler
credentials: {
accessKeyId: config.accessKeyId
secretAccessKey: config.secretAccessKey
}
})
}
配置 MinIO/R2 账号(前端操作)
- 本地启动项目:
npm run dev - 访问
http://localhost:3000/setup,进入配置中心 - 填写账号信息:
- MinIO:Endpoint 填写
http://你的MinIO地址:9000,Access Key/Secret Key 填写 MinIO 配置的密钥,Bucket Name 填写已创建的存储桶 - R2:Endpoint 填写
https://<你的账户ID>.r2.cloudflarestorage.com,Access Key/Secret Key 填写 R2 密钥,Bucket Name 填写 R2 存储桶,Public URL 填写 R2 公开访问地址(可选)
- MinIO:Endpoint 填写
- 点击「测试连接」,验证配置无误后,点击「添加并切换」,完成账号配置
4. 核心功能解读(亮点功能实现)
(1)断点续播:播放进度自动保存与恢复
断点续播功能通过将播放进度存储在存储桶的 .r2-drive-system/history.json 文件中实现,核心逻辑:
- 视频播放时,每 2 秒触发一次进度保存(节流避免频繁请求)
- 关闭预览模态框或切换页面时,自动保存最终进度
- 再次打开该视频时,从历史文件中读取进度并自动跳转
// components/PreviewModal.tsx
const handleTimeUpdate = () => {
if (!videoRef.current || !file || !config) return
// 节流保存
if (saveTimeoutRef.current) clearTimeout(saveTimeoutRef.current)
const currentTime = videoRef.current.currentTime
const duration = videoRef.current.duration
saveTimeoutRef.current = setTimeout(() => {
saveProgress(currentTime duration)
} 2000)
}
(2)全盘深度搜索:递归扫描所有文件
基于 S3 协议的 ListObjectsV2 命令,递归扫描存储桶中的所有文件,支持模糊匹配,限制最大循环次数防止超时:
// app/api/search/route.ts
do {
const command = new ListObjectsV2Command({
Bucket: config.bucketName
ContinuationToken: continuationToken
})
const response: ListObjectsV2CommandOutput = await r2.send(command)
if (response.Contents) {
const matches = response.Contents
.filter(item => item.Key && item.Key.toLowerCase().includes(lowerQuery) && !item.Key.endsWith('/'))
.map(file => ({
key: file.Key
size: file.Size
lastModified: file.LastModified
url: `${config.publicUrl}/${file.Key}`
}))
files.push(...matches)
}
continuationToken = response.NextContinuationToken
loops++
} while (continuationToken && loops < MAX_LOOPS) // 限制最大循环次数,防止超时
(3)多账户无缝切换:配置上下文封装
通过 ConfigContext 封装多账户配置,实现无缝切换,无需重新登录或刷新页面:
// context/ConfigContext.ts
export const ConfigProvider = ({ children }: { children: ReactNode }) => {
const [configs setConfigs] = useState<R2Config[]>([])
const [activeConfigId setActiveConfigId] = useState<string | null>(null)
const [isInitialized setIsInitialized] = useState(false)
// 切换账户
const switchConfig = (id: string) => {
setActiveConfigId(id)
localStorage.setItem('activeConfigId' id)
}
// 其他逻辑:添加更新删除配置...
return (
<ConfigContext.Provider value={{
config: activeConfig
configs
switchConfig
addConfig
updateConfig
removeConfig
isInitialized
}}>
{children}
</ConfigContext.Provider>
)
}
五部署到 Fly.io(一键上线,支持 IPv6)
1. 配置 fly.toml
项目中已提供 fly.toml 配置文件,核心配置如下(确保支持 IPv6 和正确端口):
# fly.toml
app = "r2-drive" # 替换为你的应用名称(全局唯一)
primary_region = "arn" # 可选,选择就近区域
[env]
PORT = "8080" # Next.js 启动端口
[[services]]
protocol = "tcp"
internal_port = 8080
processes = ["app"]
[[services.ports]]
port = 80
handlers = ["http"]
force_https = true
[[services.ports]]
port = 443
handlers = ["tls" "http"]
# 启用 IPv6(默认开启,无需额外配置)
[[services.ipv6]]
enabled = true
2. 执行部署命令
在项目根目录下执行部署命令(与你的操作一致):
fly deploy
3. 部署过程解读(对应你的部署日志)
- 验证配置:Fly.io 会先验证
fly.toml配置的有效性 - 构建镜像:通过 Depot 构建 Docker 镜像,安装 Node.js 依赖构建 Next.js 项目
- 推送镜像:将构建完成的镜像推送到 Fly.io 镜像仓库
- 滚动更新:更新现有机器,采用滚动策略,避免服务中断
- 验证 DNS:配置应用域名(
r2-drive.fly.dev),自动解析 IPv4/IPv6 地址
4. 部署后验证
(1)查看应用状态
# 查看应用基本信息
fly status
# 查看应用 IP 地址(验证 IPv6 支持)
fly ips list
执行 fly ips list 后,会显示类似如下结果,其中 ipv6 字段即为应用的 IPv6 地址:
TYPE ADDRESS CREATED AT
ipv4 xxx.xxx.xxx.xxx 2026-01-13T00:00:00Z
ipv6 2a09:8280:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx 2026-01-13T00:00:00Z
(2)访问应用
通过浏览器访问 https://r2-drive.fly.dev(替换为你的应用域名),即可看到私有云系统的前端界面:
- 进入配置中心,填写 MinIO/R2 账号信息
- 测试文件上传预览断点续播等功能
- 通过 IPv6 地址直接访问,验证 IPv6 可达性
六功能演示与进阶优化
1. 核心功能演示
- 多账户切换:在首页点击账号别名,可快速切换已配置的 MinIO/R2 账号
- 断点续播:播放一段视频后关闭,再次打开该视频,会自动恢复到上次播放的位置
- 全盘搜索:开启「全盘」搜索模式,输入文件名关键词,可检索整个存储桶中的匹配文件
- 拖拽上传:将文件/文件夹拖拽到上传区域,可批量上传,实时显示上传进度和速度
2. 进阶优化方向
(1)配置自定义域名
将 Fly.io 应用绑定自定义域名,并配置 SSL 证书,提升访问体验:
# 添加自定义域名
fly domains add your-domain.com
# 生成 SSL 证书
fly certs add your-domain.com
(2)MinIO 集群部署
若需要更大的存储容量和更高的可用性,可将 MinIO 部署为集群模式,支持分布式存储和数据冗余。
(3)自动备份策略
配置定时任务,将存储桶中的数据备份到其他设备或云存储,防止数据丢失:
- 可使用
rclone工具,定时同步 MinIO/R2 数据 - 可配置 Fly.io 定时任务,执行备份脚本
(4)扩容 Fly.io 应用
若应用访问量较大,可扩容 Fly.io 机器规格,提升性能:
# 查看可用机器规格
fly machine types list
# 扩容机器规格
fly machine update <machine-id> --type <machine-type>
七总结:数据自主,从这款私有云开始
本文从零到一搭建了一款旗舰级私有云存储系统,基于 Next.js 实现了现代化的前端界面,支持 MinIO/R2 双后端存储,通过 Fly.io 完成了轻量化部署(天然支持 IPv6,国内用户友好),核心亮点如下:
- 数据 100% 自主:存储在私有 MinIO 或 R2 桶,不受公有云服务商绑架,保障隐私安全
- 功能媲美商业云盘:断点续播全盘搜索多账户切换等功能,满足日常使用需求
- 部署简单高效:Fly.io 一键部署,预授权无实际扣费,IPv6 原生支持,无需复杂运维
- 低成本可扩展:个人使用免费额度足够,后续可根据需求扩容存储和计算资源
告别公有云的「隐形绑架」,从搭建一款属于自己的私有云开始。这款项目不仅是一个技术实现,更是数据自主理念的落地载体,希望本文能帮助你实现数字资产的可控管理,不再受限于第三方服务商的规则与约束。
附:常见问题解答
-
Q:Fly.io 预授权迟迟不退回怎么办?
A:预授权退回时间由银行决定,通常 1-3 个工作日内会解冻,可联系银行客服查询进度。 -
Q:MinIO 私有部署后,Fly.io 应用无法访问怎么办?
A:确保 MinIO 服务器开启公网访问(或配置内网穿透),防火墙开放 9000 端口,且 Fly.io 应用能访问 MinIO 地址。 -
Q:R2 用量统计无法显示怎么办?
A:确保填写了正确的 Cloudflare 账户 ID 和 API Token(需具备 Analytics 权限),且 R2 桶已开启用量统计功能。 -
Q:如何实现断点续传上传?
A:可基于tus-js-client扩展上传功能,支持大文件断点续传,后续可集成到项目中。
评论区(0 条)
发表评论⏳ 加载编辑器…