MinIO 是一个用 Go 写的 S3 兼容对象存储,单机单盘就能跑,最小配置给 1 核 1G 就能启动;它把文件存成「桶 + 对象键」的结构,因此你能用任何 S3 SDK、rclone、mc 客户端去读写,而不是只能靠 SSH 登机器翻目录。 2026 年 10 月,我在一台 2 核 4G、40G 盘的 Debian 12 VPS 上部署它来存站点备份和图片,启动命令一条,占内存约 200MB。真正需要注意的是版本变化:较新的社区版镜像已经不再内置 Web 控制台,习惯「打开浏览器点点点」的人会以为装失败了。
上面是结论。上一篇写 rsync + cron 异地备份时,我留了个尾巴——rsync 只能同步目录结构,想单独取回三个月前的某张图片,得把整条路径还原出来。这篇用对象存储把这个短板补上。

对象存储和普通目录到底差在哪?
结论:目录是「层级 + 元数据在文件系统里」,对象存储是「扁平键值 + 元数据在服务端」——后者更适合海量小文件和按 URL 直读。
| 维度 | rsync / NFS | MinIO(S3) |
|---|---|---|
| 组织方式 | 真实目录树 | 桶 + 对象键(键里带 / 只是视觉分层) |
| 取单个文件 | 需要路径 + 权限 | 一个 HTTP URL 或 SDK 调用 |
| 扩容 | 换更大的盘 | 加节点或加盘(纠删码模式) |
| 元数据 | 靠文件系统 | 自定义 metadata(Content-Type 等) |
| 适合 | 整机迁移、全量镜像 | 备份归档、图床、应用附件 |
选哪个不是技术优劣,是使用场景。整机迁移我还是用 rsync,因为要保留权限、属主、符号链接;备份归档、图片、应用上传附件走对象存储,因为按 key 取用方便、能直接给前端发 URL。

第一步:一条命令起服务
结论:单机模式就是一个容器加一个数据目录,端口 9000 走 API、9001 走控制台(新版本可能没有)。
$ mkdir -p /opt/minio/data
$ docker run -d --name minio \
--restart unless-stopped \
-p 127.0.0.1:9000:9000 \
-p 127.0.0.1:9001:9001 \
-e "MINIO_ROOT_USER=backupadmin" \
-e "MINIO_ROOT_PASSWORD=换成至少16位随机串" \
-v /opt/minio/data:/data \
minio/minio:RELEASE.2025-04-22T22-12-26Z \
server /data --console-address ":9001"
三点说明:
- 端口只绑
127.0.0.1。对象存储绝不该直接暴露公网,后面用 Nginx 或 Cloudflare Tunnel 做入口。 - 镜像 tag 写死到具体版本,别用
latest。MinIO 的社区版功能调整比较频繁,latest会给你惊喜。 MINIO_ROOT_PASSWORD低于 8 位会直接启动失败,官方建议 16 位以上。
启动后验证:
$ docker logs minio | tail -20
$ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:9000/minio/health/live
200
/minio/health/live 返回 200 就说明服务活着。这个端点可以直接接进 Uptime-Kuma 做存活监控。

第二步:先接受「没有 Web 控制台」这件事
结论:2025 年之后的社区版镜像不再内置图形控制台,访问 9001 会 404 或空白——这不是你装错了,官方把管理界面拆成了独立项目。
我第一次装完打开 http://IP:9001 看到的是空白页,检查了半小时端口、防火墙、容器日志,最后才确认是版本策略变化。判断方法很简单:
$ docker exec minio ls /usr/bin | grep -i console
$ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:9001/
如果 9001 没有正常页面,就走命令行。装 mc(MinIO Client):
$ curl -sSL https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc
$ chmod +x /usr/local/bin/mc
$ mc --version
mc version RELEASE.2025-04-16T18-13-26Z
官方容器部署文档在 MinIO Docs · Deploy MinIO with Docker,客户端用法在 mc 命令参考。
如果你确实需要图形界面,两条路:用旧版本镜像(不推荐,会失去安全修复),或者单独部署官方拆出来的 console 容器。我选了命令行,因为日常操作就那几个。

第三步:建桶、配别名、传第一批文件
结论:mc alias set 一次配好端点,之后所有命令都用别名,不用重复敲密钥。
$ mc alias set local http://127.0.0.1:9000 backupadmin '你的密码'
$ mc mb local/site-backup
$ mc ls local
[2026-10-18 21:04:12 CST] 0B site-backup/
传文件:
$ mc cp /opt/backup/2026-10-18.tar.gz local/site-backup/
$ mc ls local/site-backup
整目录同步(增量,只传变化的):
$ mc mirror --overwrite /var/www/website local/site-backup/website/
一个很实用的技巧:开版本控制。开了之后同名对象被覆盖时旧版本仍保留,误删能捞回来:
$ mc version enable local/site-backup
$ mc ls --versions local/site-backup/website/index.php
代价是空间会持续增长,需要配生命周期规则清理。备份桶我开了版本控制并设 90 天过期:
$ mc ilm rule add --expire-days 90 local/site-backup
$ mc ilm rule ls local/site-backup

第四步:rclone 挂载,让备份脚本不用改
结论:rclone 用 S3 协议对接 MinIO,关键是 provider = Minio 和 force_path_style = true,否则会拼出错误的请求地址。
配 ~/.config/rclone/rclone.conf:
[minio]
type = s3
provider = Minio
access_key_id = backupadmin
secret_access_key = 你的密码
endpoint = http://127.0.0.1:9000
force_path_style = true
force_path_style 是最容易漏的一行。默认 rclone 会用 bucket.endpoint 这种虚拟主机风格(virtual-hosted-style),MinIO 单机默认只认路径风格(endpoint/bucket/key),不设这行会报 no such host 或 403。官方说明在 rclone · S3 后端文档。
验证:
$ rclone lsd minio:
$ rclone copy /opt/backup/2026-10-18.tar.gz minio:site-backup/
$ rclone size minio:site-backup
Total objects: 42
Total size: 18.734 GiB
把原来的备份脚本改一行就行——rsync 换成 rclone sync,目标从 user@host:/path 换成 minio:site-backup/:
$ rclone sync /var/www/website minio:site-backup/website \
--transfers 4 --checkers 8 --log-file /var/log/rclone.log --log-level INFO

第五步:把公网入口和权限摆对
结论:对象存储的权限模型比文件系统粗——要么公开读整个桶,要么全私有走签名 URL,中间态要靠桶策略实现。
三种典型用法:
A. 私有桶 + 预签名 URL(备份、内部附件)
$ mc share download --expire 24h local/site-backup/2026-10-18.tar.gz
生成一条 24 小时有效的链接,过期自动失效。适合临时分享给同事。
B. 公开读桶(图床、静态资源)
$ mc anonymous set download local/public-img
之后 http://你的域名/public-img/a.jpg 可直接访问。注意这是整个桶公开,别把备份桶设成这个。
C. 桶策略限定前缀(只有 /public/* 可读)
$ mc anonymous set download local/assets/public
这个写法是给桶内的 public/ 前缀开匿名读,其余仍私有。生产环境用这个,比整桶公开安全。
公网入口我走的是 Nginx 反代 + Let's Encrypt,只反代 9000 端口,管理端口 9001 完全不对外。别直接把 9000 暴露到公网——S3 的鉴权虽然有签名,但暴露面越小越好。

踩过的四个坑
结论:path-style、版本 tag、时区、单盘无冗余——四条里前两条会让你「装完就用不了」,后两条会在半年后咬你一口。
坑一:rclone 不设 force_path_style。 报错 dial tcp: lookup site-backup.127.0.0.1: no such host,因为它在拼虚拟主机风格的域名。
坑二:latest 镜像悄悄换了行为。 我第一版用 minio/minio:latest,两周后重启容器,控制台没了、启动参数也变了。备份系统的基础组件必须锁版本,这条比什么都重要。
坑三:容器时区是 UTC。 mc ls 显示的时间和本机差 8 小时,对账时容易算错。加 -e TZ=Asia/Shanghai 或挂 /etc/localtime。
坑四:单机单盘没有冗余。 MinIO 单机单盘模式(server /data)就是普通文件存储,盘坏了数据就没了。它不是备份的目的地,它是备份的一个副本。 我的做法是本地一份 + MinIO 一份 + 云端对象存储一份,三份才算稳。真要冗余得上纠删码模式(至少 4 块盘),那就不是 40G 小机器的场景了。
常见问题
Q:MinIO 免费吗?
A:社区版 AGPLv3 免费,功能上单机/分布式基础能力都有。企业版涉及授权与商业支持,个人和小团队用社区版足够。
Q:1G 内存的小机器能跑吗?
A:能启动,但传大文件时容易 OOM。建议至少 2G,我的 4G 机器上常驻约 200MB,传 1G 以上文件时会短时冲高。
Q:能替代云厂商的对象存储吗?
A:小规模、单机房场景可以,成本也低。但云对象存储的多副本、跨区容灾、CDN 回源这些能力,自建要自己补,别指望一个容器解决。
Q:备份数据要不要加密?
A:要。MinIO 支持服务端加密(SSE-S3/SSE-KMS),但更简单的做法是备份文件本身先 gpg 或 age 加密再上传——这样即使存储被拖走,内容也读不出来。