欢迎光临

VPS 自建对象存储服务实战:用 MinIO 替代云厂商 S3,低成本搭建私有云盘与图床

为什么要在 VPS 上自建对象存储?

越来越多的开发者和中小企业在日常工作中依赖对象存储——无论是网站的图片托管、应用的上传文件归档,还是数据备份与分发。AWS S3、阿里云 OSS、腾讯云 COS 等公有云服务虽然稳定,但费用随着流量和存储量线性增长,尤其当你需要对外提供大量公开读取的文件时(比如图床、静态资源 CDN 回源),带宽费用往往远超存储费用。

一台月费 5~10 美元的 VPS,搭配开源的 MinIO 对象存储引擎,就能轻松替代公有云 S3 的核心功能,而且数据完全在自己手中,没有供应商锁定,也没有流量出口的额外计费。本文将手把手带你完成 MinIO 在 VPS 上的生产级部署,包括安全加固、域名配置、客户端工具使用,以及与常用应用(WordPress、图床)的集成方案。

MinIO 是什么?和 S3 有什么关系?

MinIO 是一款用 Go 语言编写的高性能对象存储服务器,完全兼容 Amazon S3 API。这意味着所有为 S3 开发的 SDK、CLI 工具和应用程序,只要把 endpoint 指向你的 MinIO 服务器,就能无缝切换——代码几乎不用改。

MinIO vs 公有云 S3 核心对比

维度 AWS S3 / 阿里云 OSS MinIO 自建
存储成本 $0.023/GB/月 VPS 磁盘自带,零额外费用
流量费用 $0.09/GB(公网下载) VPS 带宽包月,无按量计费
数据主权 数据在云厂商机房 数据完全自控
API 兼容性 原生 S3 S3 完全兼容
高可用 跨可用区冗余 单节点需自行备份,分布式需多机
运维成本 零运维 需自行维护服务

如果你的使用场景是单站点或中小规模(几十 GB 到几百 GB),一台 VPS + MinIO 是性价比极高的选择。大型企业或需要 99.999% 可用性的场景,仍然建议使用公有云。

环境准备与系统选型

推荐使用 Debian 12 或 Ubuntu 22.04+ 作为操作系统。MinIO 对系统要求极低:官方最低配置仅为 1 核 CPU、512MB 内存。但考虑到你可能同时运行 Nginx 等反向代理,建议至少 1 核 1GB 内存的 VPS。

磁盘是对象存储的核心。强烈建议使用 SSD 或 NVMe 硬盘的 VPS 方案,HDD 在高并发小文件场景下性能差距明显。存储目录建议挂载独立的数据盘,方便扩容和备份。

基础环境检查


1
2
3
4
5
6
7
8
9
10
11
12
# 确认系统版本
lsb_release -a

# 检查磁盘空间
df -h

# 创建数据目录
mkdir -p /data/minio

# 创建专用系统用户(安全最佳实践)
useradd -r -s /sbin/nologin minio-user
chown -R minio-user:minio-user /data/minio

安装 MinIO 服务端

MinIO 官方提供单个二进制文件,没有复杂的依赖,安装非常简单。以下使用官方推荐的稳定版本下载方式:


1
2
3
4
5
6
7
8
9
10
# 下载 MinIO 服务端(Linux amd64)
wget https://dl.min.io/server/minio/release/linux-amd64/minio \
  -O /usr/local/bin/minio

# 赋予执行权限
chmod +x /usr/local/bin/minio

# 验证版本
minio --version
# 输出示例:minio version RELEASE.2024-11-07T00-52-20Z

同时也安装官方客户端工具 mc(MinIO Client),后续配置 Bucket 和上传文件都需要它:


1
2
3
4
5
6
# 下载 mc 客户端
wget https://dl.min.io/client/mc/release/linux-amd64/mc \
  -O /usr/local/bin/mc

chmod +x /usr/local/bin/mc
mc --version

配置 systemd 服务与安全启动

生产环境务必使用 systemd 管理 MinIO 进程,确保开机自启和异常自动重启。关键是使用非 root 用户运行,并将敏感凭证放在环境文件中。

创建环境变量文件


1
2
3
4
5
6
7
8
9
10
11
12
13
# /etc/default/minio — MinIO 环境配置
# 服务端监听地址(仅本地,由 Nginx 反代)
MINIO_OPTS="--address 127.0.0.1:9000 --console-address 127.0.0.1:9001"

# 管理员账号(务必修改为强密码)
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=YourStrongPassword123!@#

# 数据目录
MINIO_VOLUMES="/data/minio"

# 区域标识(可选)
MINIO_SERVER_URL="https://s3.yourdomain.com"

将上述内容写入

1
/etc/default/minio

,并设置严格权限:


1
2
chmod 600 /etc/default/minio
chown root:minio-user /etc/default/minio

创建 systemd 服务单元


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# /etc/systemd/system/minio.service
[Unit]
Description=MinIO Object Storage
Documentation=https://min.io/docs/minio/linux
After=network.target

[Service]
User=minio-user
Group=minio-user
EnvironmentFile=/etc/default/minio
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
Restart=always
RestartSec=10
LimitNOFILE=65536
TasksMax=infinity
TimeoutStopSec=infinity
SendSIGKILL=no

# 安全加固
ProtectSystem=full
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

启动并设置开机自启:


1
2
3
systemctl daemon-reload
systemctl enable --now minio
systemctl status minio

确认服务处于 active (running) 状态即可。

Nginx 反向代理与 HTTPS 配置

MinIO 监听在 127.0.0.1,外部访问全部通过 Nginx 反代。这样做的好处是:统一 TLS 终止、灵活配置访问控制、方便加 CDN。这里推荐用两个子域名分别代理 API 和管理控制台:

  • 1
    s3.yourdomain.com

    — S3 API 端点(用于 SDK/CLI 访问)

  • 1
    console.yourdomain.com

    — MinIO Web 控制台

Nginx 配置:S3 API 端点


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# /etc/nginx/sites-available/s3.yourdomain.com
server {
    listen 443 ssl http2;
    server_name s3.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/s3.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/s3.yourdomain.com/privkey.pem;

    # 允许大文件上传(MinIO 单对象最大 5TB)
    client_max_body_size 0;

    # 禁用请求缓冲,直接透传
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 支持(控制台需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

# HTTP 重定向
server {
    listen 80;
    server_name s3.yourdomain.com;
    return 301 https://$host$request_uri;
}

Nginx 配置:Web 控制台端点


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# /etc/nginx/sites-available/console.yourdomain.com
server {
    listen 443 ssl http2;
    server_name console.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/console.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/console.yourdomain.com/privkey.pem;

    client_max_body_size 0;
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_pass http://127.0.0.1:9001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

别忘了在 Nginx 主配置中定义

1
$connection_upgrade

变量:


1
2
3
4
5
# 在 http 块中添加
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

用 Certbot 自动申请 Let’s Encrypt 证书后,启用站点并 reload Nginx:


1
2
3
4
5
6
7
8
9
# 申请证书
certbot certonly --nginx -d s3.yourdomain.com
certbot certonly --nginx -d console.yourdomain.com

# 启用站点
ln -s /etc/nginx/sites-available/s3.yourdomain.com /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/console.yourdomain.com /etc/nginx/sites-enabled/

nginx -t && systemctl reload nginx

创建 Bucket 与基础操作

MinIO 安装完成后,通过 mc 客户端配置别名并创建第一个 Bucket:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 配置 mc 连接
mc alias set myminio https://s3.yourdomain.com admin 'YourStrongPassword123!@#'

# 创建 Bucket
mc mb myminio/images
mc mb myminio/backups
mc mb myminio/static

# 查看 Bucket 列表
mc ls myminio

# 上传文件
mc cp ./photo.jpg myminio/images/
mc cp --recursive ./assets/ myminio/static/

# 设置 Bucket 为公开只读(适合图床/静态资源)
mc anonymous set download myminio/images
mc anonymous set download myminio/static

# 查看访问策略
mc anonymous get myminio/images
# 输出:Access permission for 'images' is 'download'

设置为公开下载后,任何人都可以通过 URL 直接访问文件:


1
https://s3.yourdomain.com/images/photo.jpg

这对图床和静态资源托管非常方便。但请注意:绝不要把 Bucket 设为公开上传,否则会被滥用。

实际应用场景集成

场景一:WordPress 媒体库对接 MinIO

WordPress 默认将上传文件存到本地

1
wp-content/uploads/

目录,对于 VPS 硬盘有限或需要 CDN 加速的场景,将媒体文件存到 MinIO 是更好的选择。

安装插件 WP Offload Media(免费版即可),配置步骤:

  • Storage Provider 选择 S3 兼容存储
  • Endpoint 填入
    1
    https://s3.yourdomain.com
  • Access Key 和 Secret Key 填入 MinIO 的管理员凭证(建议单独创建只读策略的子用户)
  • Bucket 填入你创建的 Bucket 名称
  • 开启「Remove files from server」选项,上传后自动删除本地副本

这样 WordPress 的所有图片、附件都会自动上传到 MinIO,页面渲染时从 MinIO 加载,大大减轻 VPS 本地磁盘压力。

场景二:自建图床服务

对于经常在博客、论坛中插入图片的用户,自建图床比依赖第三方服务更可控。最简单的方案是配合 MinIO 的公开 Bucket + 一个轻量前端。

这里推荐 PicGo——一款跨平台图床工具,支持 S3 协议上传:

  • 在 PicGo 的图床设置中选择 Amazon S3
  • 设定 Endpoint:
    1
    https://s3.yourdomain.com
  • 填入 Access Key / Secret Key
  • Bucket:
    1
    images
  • 上传后自动生成 Markdown 格式链接,直接粘贴到文章中

配合

1
mc anonymous set download

已设置的公开访问策略,上传的图片立即可通过公网访问。

场景三:应用数据备份

MinIO 作为备份存储非常实用。下面是一个自动备份数据库并上传到 MinIO 的脚本示例:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash
# backup-to-minio.sh

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/tmp/backups
MINIO_ALIAS=myminio
MINIO_BUCKET=backups

mkdir -p $BACKUP_DIR

# 备份 MySQL
mysqldump -u root -p'YourDBPassword' --all-databases \
  | gzip > $BACKUP_DIR/mysql_${DATE}.sql.gz

# 备份网站文件
tar czf $BACKUP_DIR/www_${DATE}.tar.gz /var/www/html/

# 上传到 MinIO
mc cp $BACKUP_DIR/mysql_${DATE}.sql.gz ${MINIO_ALIAS}/${MINIO_BUCKET}/
mc cp $BACKUP_DIR/www_${DATE}.tar.gz ${MINIO_ALIAS}/${MINIO_BUCKET}/

# 清理本地临时文件
rm -rf $BACKUP_DIR/*

# 保留最近 30 天的备份,自动清理旧的
mc rm --recursive --force --older-than 30d ${MINIO_ALIAS}/${MINIO_BUCKET}/

echo "Backup completed: $DATE"

加入 crontab 每天凌晨 2 点自动执行:


1
0 2 * * * /usr/local/bin/backup-to-minio.sh >> /var/log/minio-backup.log 2>&1

安全加固与权限管理

对象存储暴露在公网,安全是重中之重。以下是生产环境必须做的加固措施:

1. 使用 IAM 策略替代 Root 账户日常操作

永远不要在应用中直接使用 Root 凭证。通过 mc 管理控制台创建专用的子用户和策略:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 创建只读用户策略(适合 WordPress 读取)
cat > /tmp/readwrite-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::images",
        "arn:aws:s3:::images/*"
      ]
    }
  ]
}
EOF

# 创建用户并附加策略
mc admin user add myminio wp-user WpUserPassword456!
mc admin policy create myminio wp-images-policy /tmp/readwrite-policy.json
mc admin policy attach myminio wp-images-policy --user wp-user

2. 防火墙只暴露必要端口


1
2
3
4
5
6
7
8
9
# 只允许 Nginx 监听的 80/443 端口
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 22/tcp
ufw enable

# 确认 MinIO 端口未暴露
curl -s http://127.0.0.1:9000/minio/health/live
# 应返回 200,但外部不应能直接访问 9000 端口

3. 启用 Bucket 版本控制

版本控制可以防止误删或覆盖重要文件:


1
2
3
4
5
# 对关键 Bucket 启用版本控制
mc version enable myminio/backups

# 查看版本状态
mc version info myminio/backups

启用后即使文件被覆盖或删除,也能通过版本 ID 恢复到任意历史版本。

性能调优与监控

MinIO 在默认配置下已经相当高效,但以下调优可以进一步提升性能:

系统层调优


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 提高文件描述符限制
echo "minio-user soft nofile 65536" >> /etc/security/limits.conf
echo "minio-user hard nofile 65536" >> /etc/security/limits.conf

# 禁用磁盘 atime 更新(减少 IO)
# 在 /etc/fstab 中为数据分区添加 noatime 选项
# /dev/sdb1  /data  ext4  defaults,noatime  0  2

# 调整内核网络参数
cat >> /etc/sysctl.conf << 'EOF'
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
EOF

sysctl -p

MinIO 健康检查与监控

MinIO 内置了健康检查端点,可以配合外部监控使用:


1
2
3
4
5
6
7
8
# 集群健康检查
curl -s http://127.0.0.1:9000/minio/health/cluster

# 存活检查
curl -s http://127.0.0.1:9000/minio/health/live

# 就绪检查
curl -s http://127.0.0.1:9000/minio/health/ready

建议在 crontab 中加一个简单的监控脚本:


1
2
3
4
5
6
7
#!/bin/bash
# minio-health-check.sh
HEALTH=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:9000/minio/health/live)
if [ "$HEALTH" != "200" ]; then
    echo "MinIO health check failed! HTTP $HEALTH" | mail -s 'MinIO Alert' admin@yourdomain.com
    systemctl restart minio
fi

MinIO 还内置了 Prometheus 指标端点,如果你已有 Grafana 监控体系,只需在

1
prometheus.yml

中添加:


1
2
3
4
5
6
7
8
9
scrape_configs:
  - job_name: minio
    metrics_path: /minio/v2/metrics/cluster
    scheme: https
    static_configs:
      - targets: ['s3.yourdomain.com']
    basic_auth:
      username: admin
      password: YourStrongPassword123!@#

常见问题与排错

上传大文件报 413 Request Entity Too Large

这是 Nginx 的

1
client_max_body_size

限制。前面配置中已经设为

1
0

(无限制),如果你漏掉了这一行,补上即可。

Presigned URL 签名失败或过期

MinIO 生成预签名 URL 时依赖服务器时间。确保 VPS 时区正确并开启 NTP 同步:


1
2
timedatectl set-ntp true
timedatectl status

mc 命令报 S3 API 错误

检查

1
MINIO_SERVER_URL

是否与实际访问域名一致。如果 Nginx 反代后域名变化,MinIO 内部生成的签名 URL 会指向错误地址。

Bucket 设为公开后仍返回 403

确认 Nginx 正确转发了

1
X-Forwarded-Proto

头。MinIO 在 HTTPS 反代场景下需要知道原始协议是 HTTPS,否则签名校验会失败。

成本对比:自建 vs 云厂商

以一个典型的个人/小团队场景为例:存储 100GB 数据,每月公网下载 500GB:

方案 月存储费 月流量费 月总费用
AWS S3 $2.30 $45.00 $47.30
阿里云 OSS ¥12.00 ¥250.00 ¥262.00
VPS + MinIO(5美元/月) 包含 包含 $5.00

可以看到,当你有一定量的公网下载需求时,VPS 自建方案的成本优势非常明显——云厂商的流量费远高于存储费,而 VPS 的带宽是包月的。当然前提是你选的 VPS 带宽足够(建议至少 100Mbps 或 1TB/月流量包)。

总结

在 VPS 上用 MinIO 自建对象存储,是对公有云 S3 的高性价比替代方案,特别适合以下场景:

  • 图床和静态资源托管,需要大量公网读取但不想付流量费
  • WordPress 等应用的媒体文件远程存储
  • 应用数据和数据库的定期备份
  • 团队内部文件共享和协作

核心步骤回顾:安装 MinIO → 配置 systemd 服务 → Nginx 反代 + HTTPS → 创建 Bucket 和 IAM 策略 → 对接你的应用。整个过程不超过 30 分钟,就能拥有一个完全受控的私有 S3 存储。数据在你自己的硬盘上,不担心供应商锁定,不担心突然涨价,也不担心别人哪天关停服务。

如果你的项目正在成长,数据量逐步增加,从自建 MinIO 起步、未来再按需迁移到公有云,这是一条平滑且经济的演进路线。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » VPS 自建对象存储服务实战:用 MinIO 替代云厂商 S3,低成本搭建私有云盘与图床
分享到: 更多 (0)