如果你需要给网站、图片服务、备份脚本或 AI 应用提供兼容 S3 的对象存储,MinIO 是比把文件直接堆在 VPS 目录里更清晰的方案。本文以 Ubuntu 24.04 和 Docker Compose 为例,从部署、HTTPS、S3 客户端、生命周期、备份到安全加固完整跑通一套单节点 MinIO。
单节点 MinIO 适合个人项目、小型网站、媒体库和开发环境,不等于高可用对象存储。建议至少 2 核 4GB 内存、80GB 以上 SSD,并把数据目录放在可扩容卷上。图片和备份增长较快时,容量比 CPU 更先成为瓶颈。
| 场景 | 建议配置 | 说明 |
|---|---|---|
| 开发测试 | 1 核 2GB、40GB SSD | 少量对象,不能作为唯一备份 |
| 个人站点 | 2 核 4GB、100GB SSD | 图片、附件、构建产物 |
| 小团队生产 | 4 核 8GB、200GB+ SSD | 另配异地备份 |
如果 VPS 磁盘经常出现 I/O 飙高,先参考 VPS 磁盘 I/O 排查指南,不要把 MinIO 和数据库、编译任务堆在同一块低性能磁盘上。
sudo apt update
sudo apt install -y ca-certificates curl
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
newgrp docker
sudo mkdir -p /opt/minio/{data,config}
sudo chown -R "$USER":"$USER" /opt/minio
cd /opt/minio
不要把数据目录放在 /tmp,也不要把 9000、9001 端口直接暴露给公网。
创建 .env,使用长度足够且不复用其他服务的凭据:
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=替换为至少32位随机密码
创建 compose.yml:
services:
minio:
image: quay.io/minio/minio:latest
container_name: minio
restart: unless-stopped
env_file: .env
command: server /data --console-address ":9001"
ports:
- "127.0.0.1:9000:9000"
- "127.0.0.1:9001:9001"
volumes:
- ./data:/data
- ./config:/root/.minio
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 30s
timeout: 10s
retries: 3
启动并检查:
docker compose up -d
docker compose ps
docker logs --tail=100 minio
将 s3.example.com 和 minio.example.com 解析到 VPS,然后在 Caddyfile 中写入:
s3.example.com {
reverse_proxy 127.0.0.1:9000
}
minio.example.com {
reverse_proxy 127.0.0.1:9001
}
Caddy 会自动申请和续期证书。没有统一反向代理入口时,可先阅读 VPS 用 Caddy 配置自动 HTTPS。修改后执行:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://s3.example.com/minio/health/live
S3 API 和 Console 使用不同域名,避免把管理界面和程序上传入口混在一起。
登录 https://minio.example.com 后创建 uploads bucket。不要让应用使用 root 账号,在 Access > Users 创建专用用户,并只绑定所需策略:
{
"Version": "2012-10-17",
"Statement": [
{"Action": ["s3:GetBucketLocation", "s3:ListBucket"], "Effect": "Allow", "Resource": ["arn:aws:s3:::uploads"]},
{"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"], "Effect": "Allow", "Resource": ["arn:aws:s3:::uploads/*"]}
]
}
应用端只保存 API 域名、Access Key、Secret Key、bucket 和 region(通常为 us-east-1)。前端直传使用短时效 presigned URL,不要把 Secret Key 放进浏览器代码。
aws configure --profile minio
aws --profile minio --endpoint-url https://s3.example.com s3 ls
echo "minio test" > /tmp/minio-test.txt
aws --profile minio --endpoint-url https://s3.example.com s3 cp /tmp/minio-test.txt s3://uploads/health/minio-test.txt
aws --profile minio --endpoint-url https://s3.example.com s3 cp s3://uploads/health/minio-test.txt -
出现 SignatureDoesNotMatch 时,检查 endpoint 是否多了路径、系统时间是否准确、反向代理是否改写 Host,以及客户端是否启用了虚拟主机风格地址。
在 Bucket > Lifecycle Rules 中为临时对象设置过期时间,例如 tmp/ 7 天、backups/ 30 天。持续关注:
df -h /opt/minio/data
du -sh /opt/minio/data/*
docker stats minio --no-stream
磁盘使用率达到 80% 就应扩容或清理,90% 时不要再等待。/data 目录不是备份,至少保留一份异地副本:
mc alias set local https://s3.example.com ACCESS_KEY SECRET_KEY
mc alias set backup https://backup-s3.example.net BACKUP_KEY BACKUP_SECRET
mc mirror --overwrite --remove local/uploads backup/minio-uploads
备份脚本应记录退出码、对象数量和耗时,并定期抽查恢复。可继续阅读 VPS 备份恢复演练指南。
.env权限设为600,不要提交到 Git:chmod 600 /opt/minio/.env。- 只开放 SSH、80、443;9000/9001 保持本机监听。
- 为每个应用创建独立 Access Key,按 bucket 和动作限制权限。
- 关闭不需要的匿名访问,公共下载使用只读策略或临时 URL。
- 配置磁盘、容器、证书和备份告警,每月至少做一次恢复测试。
- MinIO 镜像固定到经过测试的版本,升级前先备份并查看发布说明。
确认浏览器访问的是 Console 域名,而 S3 endpoint 填的是 API 域名;同时检查 bucket policy、用户策略和 CORS。不要把 minio.example.com 当作 S3 endpoint。
检查 Caddy 是否保留 Host 头、DNS 是否指向当前 VPS、系统时间是否准确。S3 签名依赖请求 Host 和时间,代理层改写任一项都可能导致鉴权失败。
确认 Compose 使用了正确的挂载路径,并执行 docker inspect minio 查看 Mounts。错误工作目录可能让容器挂载到另一处空目录。
单节点 MinIO 的关键不是把容器启动起来,而是把 API 域名、管理域名、最小权限、磁盘告警和异地备份一起设计好。个人项目可以从 2 核 4GB 起步;一旦对象存储成为唯一数据副本,就应增加独立备份,甚至迁移到多节点或托管 S3 服务。
