让备份不再依赖 rsync 目录:MinIO 单机对象存储 + rclone 挂载实录(2026)

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

上面是结论。上一篇写 rsync + cron 异地备份时,我留了个尾巴——rsync 只能同步目录结构,想单独取回三个月前的某张图片,得把整条路径还原出来。这篇用对象存储把这个短板补上。

MinIO 的读写路径

对象存储和普通目录到底差在哪?

结论:目录是「层级 + 元数据在文件系统里」,对象存储是「扁平键值 + 元数据在服务端」——后者更适合海量小文件和按 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"

三点说明:

  1. 端口只绑 127.0.0.1。对象存储绝不该直接暴露公网,后面用 Nginx 或 Cloudflare Tunnel 做入口。
  2. 镜像 tag 写死到具体版本,别用 latest。MinIO 的社区版功能调整比较频繁,latest 会给你惊喜。
  3. 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 做存活监控。

步骤 1:启动容器

第二步:先接受「没有 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 容器。我选了命令行,因为日常操作就那几个。

步骤 2:安装 mc 客户端

第三步:建桶、配别名、传第一批文件

结论: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

步骤 3:建桶与上传

第四步: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

步骤 4:rclone 对接

第五步:把公网入口和权限摆对

结论:对象存储的权限模型比文件系统粗——要么公开读整个桶,要么全私有走签名 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 的鉴权虽然有签名,但暴露面越小越好。

步骤 5:权限与入口

踩过的四个坑

结论: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 加密再上传——这样即使存储被拖走,内容也读不出来。

相关阅读

上一篇 容器日志把 40G 系统盘吃满:Docker 日志轮转的四个配置点(2026)