当前 MinIO 仍然是开源软件,但它已经不再是过去那个“Apache 2.0、社区仓库持续维护、预编译二进制直接使用”的默认选择。
写在前面
过去几年,我在很多文章里使用 MinIO 作为 S3 兼容对象存储示例。
原因很简单:它轻量、易部署、S3 API 兼容度高,非常适合本地开发、CI、演示环境和小规模私有化场景。很多时候,只要启动一个 MinIO 服务,再配合 AWS SDK、mc、rclone 或应用自身的 S3 配置,就可以把“对象存储”这件事跑起来。
但技术文章和开源项目的节奏不同。文章会长期留在互联网上,而软件项目的许可证、维护方式、发布方式都会变化。过去合理的默认选择,不代表今天也是相同的答案。
这次我重新审视 MinIO,主要是因为三件事叠加在了一起:许可证从 Apache 2.0 切换到 AGPLv3;公开 GitHub 仓库已经归档并标注不再维护;社区版预编译二进制也不再继续发布和维护。
MinIO 官方在 2021 年宣布,随着 RELEASE.2021-05-11T23-27-41Z,MinIO server、client 和 gateway 完成向 GNU AGPLv3 的迁移;官方文章也说明,虽然部分贡献代码仍保持 Apache 2.0,但 MinIO server、gateway 和 client 的整体许可证已经是 AGPLv3。根据官方文章中(《From Open Source to Free and Open Source, MinIO is now fully licensed under GNU AGPLv3》)的说法,将变更为 AGPLv3 协议后的代码的 PR 合并到自己的仓库,可能也是有一些协议风险的。
与此同时,社区里也出现了不同方向的 fork。高星的 PGSTY/Silo 仍然是 AGPLv3;JuiceData fork 虽然是 Apache 2.0,但更偏 JuiceFS S3 Gateway 场景,且代码基线和依赖相对较旧,go.mod 仍锁定在 go 1.18。
现有 MinIO 社区 fork 各有价值,高星的 PGSTY/Silo 仍是 AGPLv3,JuiceData fork 虽是 Apache 2.0,但更偏 JuiceFS 使用场景,且代码基线和依赖较旧,锁定 go1.18。
因此,我选择基于 MinIO 最后的 Apache 2.0 版本整理自己的主线,作为后续开源软件 OtterIO 的代码基础。关于 OtterIO,我们后续再单独展开。
当然,你也可以考虑切换到其他的项目和技术栈,试试 SeaweedFS 或者 RustFS。在开始之前,我们需要先了解 MinIO 和它的社区 fork 们的状态。
当前 MinIO 开源仓库发生了什么变化
先说清楚:我并不是说 MinIO “不是开源软件”了。当前 MinIO 仍然以 AGPLv3 形式开源。真正变化的是:它已经不再是我过去文章中默认使用的那个 Apache 2.0、社区仓库持续维护、预编译二进制持续发布的 MinIO。
截至 2026 年 6 月 6 日,minio/minio 仓库页面显示,它已在 2026 年 4 月 25 日被拥有者归档,进入只读状态。README 中也明确写着 “THIS REPOSITORY IS NO LONGER MAINTAINED.”,并推荐使用 AIStor Free 和 AIStor Enterprise。除此之外,当前 MinIO README 还写明,MinIO Community Edition 现在是 source-only distribution,不再提供社区版预编译二进制;历史二进制仍可作为参考,但不会继续维护,也不会接收更新。
这几个变化叠加后,我过去文章中那种“默认用 MinIO 作为本地 S3 兼容对象存储”的写法,就需要重新评估了。
这不是对 MinIO 历史价值的否定。MinIO 曾经极大降低了开发者使用 S3 兼容对象存储的门槛,也影响了大量开发者、项目和技术文章。
但对我来说,继续在旧文章中无说明地推荐它,已经不太合适。
因为很多读者的使用场景可能不只是本地实验,还会涉及私有化部署、产品集成、商业交付或二次分发。为了降低这些场景中的合规判断成本,我需要一条许可证边界更清楚、代码来源更可审计、维护面更可控的 Apache 2.0 代码基线。
PGSTY/Silo:现代社区维护 fork,但仍是 AGPLv3
社区里比较活跃的一个方向,是 PGSTY 维护的 Silo,也就是 pgsty/minio。
它的 README 明确写着,这是一个由 Pigsty 维护的 community-maintained fork,不隶属于、不受 MinIO, Inc. 认可或赞助;“MinIO” 仅用于说明上游项目来源。README 也说明它相对上游的变更较小,主要是恢复 embedded management console version reference,以及更新文档链接和 Go module path。
PGSTY/Silo 的优势很明显:补上了当前社区使用者很关心的部分:文档、服务端和客户端的 Docker Hub 仓库、补充了控制台的衍生版、支持了 Ansible 部署,以及提供了 APT/YUM 的二进制仓库。
从它的发布记录看,Silo 并不是简单镜像一份旧代码。它的 release note (所有变更记录) 中记录了安全加固、依赖升级、Go 工具链升级、OIDC/LDAP/S3 Select/复制元数据等方面的修复和调整。PGSTY/Silo 更接近于延续较新的 MinIO AGPLv3 代码形态,并补齐社区分发、文档、镜像和包管理体验。
但是,PGSTY/Silo 仍然是 AGPL-3.0 license。README 和 GitHub license 区域都明确显示它以 GNU AGPLv3 / AGPL-3.0 分发。
所以,它适合的场景是:
你接受 AGPLv3,希望继续使用较新的 MinIO 代码形态,并希望社区补上二进制、镜像、文档和部署体验。
但,我最关心的问题是:
我需要一条 Apache 2.0 的、许可证边界更宽松、更适合作为本地开发、私有化测试和后续项目基础的 MinIO 旧基线。
这就需要看另一个方向:JuiceData/minio。
JuiceData/minio:最明确的 Apache 2.0 fork,但定位更偏 JuiceFS
juicedata/minio 它的 GitHub 页面描述就是 “Fork of MinIO under Apache 2 License”,README 也保留了 “released under Apache License v2.0” 的描述,GitHub license 区域显示为 Apache-2.0。
从许可证角度看,这是目前最明确的 Apache 2.0 MinIO fork 之一。
这个项目默认分支为 new-base。和上游 minio/minio 的 compare 页面显示,juicedata:minio:new-base 相对 minio:master 有 49 次提交和 141 个文件变动记录。
从 PR 记录看,JuiceData fork 在 2024 到 2026 年仍有维护动作。例如,#83 “Fix infinite loop in MakeBucketWithLocation” 于 2026 年 5 月合并,#82 处理 invalid ETag error,#81 优化大目录 listing 时的内存使用,#79 更新 JWT 依赖以处理安全告警,#78 修复 nil pointer panic。此外,JuiceData fork 在 #54 到 #83 这一段 PR 中持续接收了不少修复和维护工作,其中一部分已经合并,另一部分关闭或被替代。
不过,我在评估它时看到两个需要进一步考虑的问题。
第一个问题和代码基线相关。
JuiceData fork 的代码基线仍然比较旧。它的 go.mod 中 Go 版本是 1.18,同时还能看到 gorilla/mux v1.8.0、较旧版本的 minio-go/v7、golang.org/x/crypto v0.11.0、golang.org/x/net v0.10.0 等依赖。
这并不是说 JuiceData 做错了。
从 JuiceFS 文档看,JuiceFS S3 Gateway 本身就是通过 MinIO S3 Gateway 实现 S3 协议访问,利用 MinIO 的对象接口把 JuiceFS 文件系统作为 MinIO server 的后端存储。因此,JuiceData fork 更像是为了 JuiceFS 相关场景维护一条能工作的 Apache 2.0 MinIO 旧基线,而不是为了做一个面向所有 MinIO 用户的通用替代发行版。
对我来说,与其继续围绕旧依赖做补丁,不如趁这次整理把 HTTP router 和相关依赖一起收敛。
第二个问题和代码来源相关。
在评估 Apache 2.0 fork 时,不能只看仓库根目录的 LICENSE 文件,还要看后续合入代码的来源。
如果一个 fork 的基线来自 RELEASE.2021-04-22T15-44-28Z 或更早的 Apache 2.0 MinIO,那么这部分代码的许可证边界比较清楚。该 tag 的 LICENSE 是 Apache License 2.0;而到 RELEASE.2021-05-11T23-27-41Z,LICENSE 已经变为 GNU AGPLv3。
后续新增代码则需要分情况判断。
Apache License 2.0 第 5 条有默认贡献规则:除非贡献者明确说明其他条款,否则有意提交给项目的 contribution 会按该许可证条款提交;同时它也保留“若存在单独签署的许可协议,则以单独协议为准”的空间。
所以,如果贡献者直接向 Apache 2.0 fork 提交 PR,并没有额外标记 “Not a Contribution” 或其他许可证限制,通常可以按该 fork 的 Apache 2.0 规则理解。
但如果代码是从 AGPLv3 之后的上游 MinIO 主线 cherry-pick、复制或改写而来,就不能简单因为目标仓库是 Apache 2.0,就自动把它恢复成 Apache 2.0。AGPLv3 对修改版本和整体作品的授权方式有自己的要求,不能被目标仓库的 LICENSE 文件单方面覆盖。
这也是我不想直接拿现有 JuiceData Apache fork 作为最终底座的原因之一。
我希望自己的主线能明确说明起点、代码来源、合入范围和安全修复方式,尽可能减少许可证和来源追踪上的不确定性。
这不是对 JuiceData fork 的否定,而是我作为下游维护者对自己仓库边界的要求。
对我来说,juicedata/minio 是非常重要的参考对象:它证明 Apache 2.0 MinIO 旧基线仍然有继续维护的价值。但它并不是我想直接拿来作为后续文章和项目基础的最终答案,因为它的定位更偏 JuiceFS 生态,Go 版本和依赖基线也没有完全更新到我希望长期维护的状态。
soulteary/minio:整理一份可开源审计的 Apache 2.0 主线基础
最终,我整理了自己的 soulteary/minio 主线(基础改动后,已经存档固定)。
有了前文的铺垫,你大概已经知道我会怎么做了。
选择 “安全协议”的代码基础
这个仓库不是从当前 AGPLv3 MinIO 主线继续开发,也不是简单镜像某个社区 fork,而是和 JuiceData 一样,基于 MinIO 切换到 AGPLv3 之前的最后 Apache 2.0 版本进行整理。
参考 PGSTY/Silo 一样,我也在仓库文档中明确声明了:
这是一个独立的社区维护 fork,不隶属于、不受 MinIO, Inc. 认可或赞助;MinIO 商标仅用于说明上游来源;Apache 2.0 不授予商标权;该 fork 基于 MinIO 改用 GNU AGPLv3 之前的最后 Apache 2.0 release,并继续以 Apache License 2.0 分发。
这些声明很重要。Apache 2.0 允许复制、修改和分发代码,但并不授予商标权;许可证第 6 条也明确说明,除合理说明作品来源和复现 NOTICE 内容外,不授予使用 licensor 商号、商标、服务标记或产品名称的许可。
为了方便后来者,仓库描述中也明确写着它基于 RELEASE.2021-04-22T15-44-28Z。这样,如果有人之后想做类似工作,至少能从一个更清楚的代码基线开始。
或许,可以让大家在做类似工作能够省点事儿。
“激进一些”的代码整理
和 JuiceData fork 相比,我的主线不只是保留旧代码,而是继续做了更激进的整理。
HTTP 层从 gorilla/mux 切换到 gofiber/fiber/v3;Bucket Notification 功能只保留 elasticsearch、mysql、postgresql、redis 和 webhook;移除了 Kafka、NATS、NATS Streaming、NSQ、AMQP、MQTT 等消息队列目标;Gateway 只保留 nas 和 s3,移除 azure、gcs 和 pdfs;工具链升级到 Go 1.26 或更新版本。
从 go.mod 也可以看到,主线已经切到 Go 1.26,并升级了不少关键依赖,例如 gofiber/fiber/v3、apache/thrift、coredns/coredns、klauspost/compress 等等。
我没有试图维护一个“完整 MinIO 替代品”。
我的目标更窄:保留本地开发、CI、私有化测试和轻量部署场景中最常用的 S3 兼容对象存储能力,同时删掉那些对当前目标无关、却会持续增加依赖、CVE、构建和审计成本的功能。
对基础设施软件来说,功能越多并不一定越安全。
每多一个 Gateway,每多一个通知后端,每多一个旧依赖,就多一组安全告警、多一组升级成本、多一组需要回归测试的边界条件。
所以,这次整理的核心不是“追求完整复刻 MinIO”,而是反过来问:
- 哪些能力是我确实需要的?
- 哪些能力只是历史包袱?
- 哪些依赖会持续增加安全和维护成本?
- 哪些功能可以删除,让项目更容易长期维护?
减少维护面,本身就是一种安全收益。
为什么最终会有 OtterIO
soulteary/minio 是整理代码历史和安全基线的过渡仓库。它的名字仍然保留 MinIO,是为了明确说明上游来源和 fork 关系。
但从长期看,继续使用 MinIO 这个名字并不合适。
Apache 2.0 允许复制、修改和分发代码,但并不授予商标权。继续用 MinIO 作为项目名称,容易造成用户认知上的混淆,也不利于清楚表达这是一个独立维护的派生项目。
因此,soulteary/minio 完成整理后需要被存档,后续主线也需要一个新的仓库来承载。
这就是我创建 soulteary/otterio 的原因。
简单来说,soulteary/minio 的意义是“整理和验证 Apache 2.0 MinIO 旧基线”。而 OtterIO 的意义是“给这条整理后的代码线一个新的项目边界、名称和后续维护空间”。
更具体地说,OtterIO 要解决的不只是“换一个名字”的问题,而是把这条 Apache 2.0 代码线项目化:它需要有新的项目身份、独立的分发方式、清楚的安全基线、可追踪的安全修复记录,以及面向实际使用场景的部署文档。
当前 OtterIO README 已经明确说明,它是一个高性能、S3 兼容的对象存储服务,也是一个独立的、由社区维护的 MinIO 分支;项目未获得 MinIO, Inc. 的关联、认可或赞助,并继续以 Apache License 2.0 分发,保留原始版权声明。
这也是我希望 OtterIO 和 soulteary/minio 分开的原因:soulteary/minio 负责回答“代码从哪里来、许可证边界是否清楚、旧基线是否能够被现代化整理”的问题;OtterIO 则负责回答“这个整理后的代码线如何作为一个新的项目被使用、分发、审计和继续演进”的问题。
目前 OtterIO 已经不只是一个改名仓库。它已经有自己的容器镜像,发布在 Docker Hub 的 soulteary/otterio 和 GitHub Container Registry 的 ghcr.io/soulteary/otterio;文档中也区分了 latest 稳定版和 edge 测试构建。
安装路径也不再只是“自己 clone 代码然后编译”。OtterIO 当前文档已经提供 Docker、macOS Homebrew、Linux 二进制、Windows 二进制和源码构建方式;Linux 构建产物覆盖 amd64、arm64、arm、ppc64le、s390x,并同时提供 .deb 与 .rpm 软件包。这件事对我和用户都很重要:如果一个项目想替代旧文章中“拿来就能跑”的 MinIO 示例,它就不能只停留在源码仓库层面,而应该提供足够简单、稳定、可重复的获取方式。
安全基线方面,OtterIO 也已经把规则写得更明确:因为它来自 2021 年 4 月 22 日左右的 Apache 2.0 MinIO 基线,之后上游 minio/minio 的每一个 CVE / GHSA 都会被先视为“可能适用”,再进入 backlog 进行逐项确认、回补或标记为不适用。当前 SECURITY 文档记录的状态是:14 个已关闭、2 个不适用、0 个开放;新的上游安全公告会进入同一张表,并以 Pending 状态开始跟踪。
或许,这会比简单写一句“我修了一些 CVE”更重要。
因为对基础设施软件来说,安全维护不能只靠一次性热情,而需要一个可持续的流程。OtterIO 的安全 backlog 不是只列标题,而是把上游参考、OtterIO 代码路径、修复状态和回归测试都放在一起。README 中的安全加固摘要也已经覆盖了 SSE 元数据注入、预条件 GET / HEAD 元数据泄露、SSE-KMS 上下文绑定、服务账号提权、AddUser 权限字段、LDAP DN 规范化、Bucket / IAM policy 解析、SigV4 与 chunked upload、复制头权限门、CVE-2023-28432 bootstrap 信息泄露,以及多值 Host 头走私审计等方向。
这意味着 OtterIO 并不是简单地“拿 2021 年的老代码继续跑”。它更像是在一个许可证边界清楚的旧基线上,重新建立安全审计、回补和测试约束。
功能取舍上,OtterIO 也延续了 soulteary/minio 这条主线的思路:不追求完整复刻 MinIO,而是保留更适合当前目标的核心能力。它的 HTTP 请求路由已经基于 gofiber/fiber/v3,不再使用 gorilla/mux;Bucket Notification 只保留 elasticsearch、mysql、postgresql、redis 和 webhook;消息队列类通知目标 Kafka、NATS、NATS Streaming、NSQ、AMQP、MQTT 已经移除;Gateway 只保留 nas 和 s3,移除了 azure、gcs 和 hdfs;构建工具链要求 Go 1.26 或更新版本。
部署体验上,OtterIO 也开始加入一些更贴近实际使用的调整。比如它支持把 S3 API 和 Web 控制台 / Admin API 拆分到不同端口:S3、STS、HealthCheck、Metrics 可以只放在 S3 端口,而 Web 控制台和 Admin API 放到控制台端口,这样反向代理、防火墙和网络策略就可以分别管控。在此基础上,OtterIO 还支持为控制台监听器配置独立 TLS 证书,让 S3 API 和控制台可以使用不同的证书目录。
不过,我并不想把 OtterIO 包装成一个“可以无脑替代所有对象存储”的项目。
OtterIO README 文档中也做了明确提醒,采用前应该根据自己的部署上下文评估,包括工作负载、容量和吞吐目标、合规与数据驻留要求、版本支持策略,以及组织内部的变更管理要求;基础设施组件上线前也应该经过实验环境、预发环境再到生产环境的分阶段验证。中文文档中同样做了提醒,单节点 OtterIO 只适合开发与评估场景,生产部署应该使用启用纠删码的分布式模式,并参考分布式部署文档。
所以,OtterIO 的目标不是成为一个宏大的“替代所有对象存储”的计划。它只是给我过去大量文章里的 S3 兼容对象存储示例,以及未来本地开发、CI、私有化测试和轻量部署场景,提供一条更清楚、更可控、更容易解释的路径。
从这个角度看,soulteary/minio 是一次代码历史和许可证边界的整理;而 OtterIO 则是这次整理之后真正面向使用者的新起点。
最后
开源项目选型,其实需要看很多维度。不能只看 Star、下载量和过去经验。还要看许可证是否适合自己的使用场景,公开仓库是否继续维护,二进制分发是否稳定,社区是否还能参与,代码来源是否清楚,安全修复是否可追踪。
MinIO 曾经是我文章里的默认对象存储示例,我们曾经许多项目中也承载了恐怖的数据存储和调用量。它的历史价值不需要否认。
整理 soulteary/minio:从最后的 Apache 2.0 MinIO 版本出发,删减不需要的功能,升级依赖,回补安全修复,明确许可证和商标边界。
这一步不是终点,它只是 OtterIO 的起点。
下一篇文章里,让我们聊聊从 MinIO 到 OtterIO:一次关于 S3、本地对象存储和开源可持续性的整理。
—EOF