
如何自建兼容S3协议的对象存储-MinIO
前言
MinIO是什么?
MinIO is an object storage solution that provides an Amazon Web Services S3-compatible API and supports all core S3 features. MinIO is built to deploy anywhere - public or private cloud, baremetal infrastructure, orchestrated environments, and edge infrastructure.
翻译过来就是说:MinIO 是一个对象存储解决方案,提供与 Amazon Web Services S3 兼容的 API,并支持所有核心 S3 功能。MinIO 可部署在任何地方——公有云或私有云、裸机基础设施、编排环境以及边缘基础设施。
有什么用?
这就得看你需求,我刚好专门买了一台大硬盘服务器拿来搞存储节点,顺手就自建一个,话不多说教程开始
服务器配置要求?
没啥大的要求我存储服务器也才1C2G,咱存储节点就不要上啥面板啥的了,内存本来就不大,docker啥的我都不建议使用
正文开始
准备工作
一台服务器装好系统,本次以Debian12为例
SSH软件(本教程采用Termius)
聪明的脑袋瓜,勤劳的双手
更新系统的软件包列表和已安装的软件包
sudo apt update && sudo apt upgrade -y
下载软件包
wget https://dl.min.io/server/minio/release/linux-amd64/minio_20250422221226.0.0_amd64.deb
ls
安装软件包
sudo dpkg -i minio_20250422221226.0.0_amd64.deb
创建用户和组
创建 minio-user
用户和组: 使用以下命令创建一个专门用于运行 MinIO 服务的系统用户(没有家目录,不能用于登录):
sudo adduser --system --no-create-home --group minio-user
--system
: 创建一个系统用户。--no-create-home
: 不需要为这个服务用户创建家目录。--group
: 同时创建一个与用户名同名的组 (minio-user
),并将用户添加到该组。
创建数据存储目录并设置权限
MinIO 需要一个专用的目录来存储对象数据。创建一个目录,并确保运行 MinIO 服务的用户对此目录有读写权限。
sudo mkdir -p /data/minio
sudo chown minio-user:minio-user /data/minio
当然了此处我的路径是/data/minio,你们可以视情况调整
配置 MinIO Systemd 服务环境变量
MinIO 的 Systemd 服务通常通过 /etc/default/minio 文件读取配置。你需要编辑这个文件来设置 MinIO 的 Root 用户、密码和数据存储路径等。我们将配置 MinIO 控制端监听在9000 端口,API端我们监听在9001端口。我推荐大家采用Nginx反代来配置域名,不建议使用IP+端口的形式
sudo nano /etc/default/minio
为什么是这个文件?
有人肯定有这个疑问,没事,我们来看MinIO Systemd 配置文件里面的内容
sudo systemctl cat minio.service
可以看见里面内容,我已经对所有内容进行全部解读
# /lib/systemd/system/minio.service
[Unit]
# 为服务提供人类可读的描述,显示在 systemctl status 等命令中。
Description=MinIO
# 指定 MinIO 官方文档的 URL。
Documentation=https://docs.min.io
# 表示一个弱依赖关系 (weak requirement)。服务希望网络在线 (network-online.target),
# systemd 会尝试与此服务一同启动 network-online.target。
# 但是,如果 network-online.target 启动失败,minio.service 仍会尝试启动。
Wants=network-online.target
# 指定启动顺序依赖。此服务仅在 network-online.target 成功激活后才会启动,确保网络连接已建立。
After=network-online.target
# 在启动服务前,systemd 会验证指定的文件 (/usr/local/bin/minio) 是否存在且具有执行权限。
# 如果条件不满足,服务启动将失败。
AssertFileIsExecutable=/usr/local/bin/minio
[Service]
# 指定服务的启动类型。'notify' 表示服务守护进程在完成启动后会通过 sd_notify 向 systemd 发送通知消息。
# 这让 systemd 可以精确跟踪服务何时真正准备就绪。
Type=notify
# 设置执行进程(MinIO 服务器)的工作目录。
WorkingDirectory=/usr/local
# 指定运行 MinIO 进程的系统用户账户。以专用的非 root 用户运行可以增强安全性。
User=minio-user
# 指定运行 MinIO 进程的系统用户组账户。
Group=minio-user
# 一项安全特性(需要较新内核/systemd)。设置为 'invisible' 时,
# 该服务的进程对同一用户运行的其他进程是隐藏的,防止意外的信号发送或进程窥探。
ProtectProc=invisible
# 从指定文件 (/etc/default/minio) 加载环境变量。
# 这些变量(如 $MINIO_OPTS, $MINIO_VOLUMES)可以在 ExecStart 命令中使用。
# 前缀 '-' 表示如果此文件丢失,服务启动*不会*失败。
EnvironmentFile=-/etc/default/minio
# 定义用于启动 MinIO 服务器进程的实际命令和参数。
# 它使用了从 EnvironmentFile 加载的变量。
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES
# 配置服务自动重启策略。'always' 表示如果 MinIO 进程因任何原因退出
# (如崩溃、收到信号、非 0 退出码的正常退出),systemd 都会自动尝试重启它,
# 除非是被 `systemctl stop` 命令明确停止的。
Restart=always
# 设置 MinIO 进程可以拥有的最大打开文件描述符(文件、套接字)数量的资源限制。
# 1048576 是一个高数值,通常是高并发服务器所需要的。
LimitNOFILE=1048576
# 禁用 systemd 基于 cgroup 的内存计费功能。
# 注释表明这样做可能是因为它存在缺陷或会干扰 MinIO 的性能。
MemoryAccounting=no
# 设置服务 cgroup 内可以创建的最大任务(线程/进程)数量。
# 'infinity' 表示 systemd 不施加限制(但内核本身的限制仍然适用)。
TasksMax=infinity
# 禁用服务启动、停止或重启操作的超时限制。
# systemd 将无限期等待服务发出就绪信号 ('notify') 或完成停止过程。
# 对于可能需要很长时间进行初始设置或优雅关闭的服务很有用。
TimeoutSec=infinity
# 调整此进程被 Linux 内存不足 (Out-Of-Memory, OOM) killer 杀死的可能性评分。
# -1000 是最低可能值,使得 MinIO 进程在系统内存紧张时极不容易被 OOM killer 选中杀死,从而保护其稳定运行。
OOMScoreAdjust=-1000
# 当停止服务时,如果进程在收到停止信号(默认为 SIGTERM)后,在超时时间(TimeoutStopSec,此处默认为 TimeoutSec=infinity)内没有退出,
# systemd 通常会发送 SIGKILL 强制终止。将此项设为 'no' 可以阻止 systemd 发送 SIGKILL。
# 这依赖于 MinIO 进程能够正确处理 SIGTERM 信号并最终自行优雅退出,无论花费多长时间。
SendSIGKILL=no
[Install]
# 指定当此服务被启用 (enabled) 时(通过 `systemctl enable minio.service`),
# 应在 `multi-user.target` 的 `.wants` 目录下创建一个符号链接。
# 这确保了当系统启动到标准的多用户运行级别 (runlevel) 时,该服务会自动启动。
WantedBy=multi-user.target
# 信息性注释,很可能是在软件包构建过程中自动添加的。
# 它指明了生成此服务文件的源项目名称和版本。
# ${...} 语法表明是构建时被替换的变量。
# Built for ${project.name}-${project.version} (${project.name})
我们只需要看见这行就行
EnvironmentFile=-/etc/default/minio
里面已经指定了默认配置文件,看到这里你的疑惑应该已经消失了.
继续配置环境变量
有些人使用Centos 一类的系统系统自带的是vim编辑器,nano肯定没咋用过,本教程也就顺带提一嘴.
键入sudo nano /etc/default/minio之后我们会来到这个界面
我们需要配置的也就几个环境变量
# MinIO 默认配置文件
# 设置数据存储卷路径
MINIO_VOLUMES="/data/minio"
# 设置传递给 minio server 的命令行参数
# API 监听端口 9001, 控制台监听端口 9000
MINIO_OPTS="--address :9001 --console-address :9001"
# 设置 MinIO Root 用户凭证
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=admin
修改成自己的信息后复制,在界面直接按住Ctrl+Shift+V
即可粘贴
保存步骤:
按 Ctrl+X
,然后按 Y
,最后按 Enter
保存退出。
重新加载 Systemd 配置并启动 MinIO 服务
sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio
sudo systemctl status minio
sudo systemctl daemon-reload
重新加载systemctl 配置文件
sudo systemctl enable minio
开机自启动MinIO
sudo systemctl start minio
启动MinIO
sudo systemctl status minio
查看MinIO服务状态
如果你是按照本教程一步一步来的话运行这四条命令,它的结果应该是
为什么报错了?有人看见自己辛辛苦苦跟着作者在敲了半天键盘,最后跑不起来,心态都没了.没事的跑不起来很正常,我们来排查就行,我写这个的目的也是让大家有排查的手段。
先看日志我们输入这个命令
journalctl -u minio.service -n 100 --no-pager
-u minio.service
:只显示这个服务的日志。-n 100
:显示最近的 100 行(可以根据需要调整)。--no-pager
:直接输出到终端,而不是使用 less 等分页器。你也可以去掉
-n 100
来查看所有相关日志,或者使用-f
来实时跟踪新日志。
看错误信息,原来是我们控制端和API端端口配置成相同的了
sudo nano /etc/default/minio
我们修正一下
# API 监听端口 9001, 控制台监听端口 9000
MINIO_OPTS="--address :9001 --console-address :9000"
再次运行,怎么还是失败,我们还是老规矩来排查
原来是我们密码最少要8位数字,在配置文件里面把密码修改一下,再次运行
sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio
sudo systemctl status minio
这不就跑起来了吗
MinIO基础使用教程
我们访问控制台端口我这里是
http://192.168.111.10:9000/login
登录之后界面是
我们点击Create a Bucket.
我们随便取一个bucket名字就行
我们点击刚才创建好的bucket,更改权限为public,方便我们外部访问,我们随便上传一个图片
如何外部访问呢,这里就要用到我们的API端口url格式是IP+API端口/bucket/文件名字
比如我们实例这个url就应该是:http://192.168.111.10:9001/local-debian/2025-04-27_21-17-54.png
如何在支持S3的程序上对接呢?
我这里以halo为例
bucket名称填你自己的bucket名称
EndPoint填API端点
风格是Path Style
那俩key在
region在这里
设置好后记得点击重启
这样就对接好了
Nginx配置反向代理
我们使用这个对象存储肯定不能将ip和端口直接暴露出去吧,我们采用nginx来反代
安装Nginx
sudo apt install nginx -y
查看状态
sudo systemctl status nginx
确认 Nginx 正在运行 (active (running))。
推荐配置
修改 MinIO 监听地址: 为了提高安全性,最好让 MinIO 只监听本地回环地址 (
127.0.0.1
),这样只有本机上的进程(比如 Nginx)才能连接它。编辑 MinIO 配置文件:
sudo nano /etc/default/minio
修改
MINIO_OPTS
行,在端口前加上127.0.0.1:
# 原来的配置:
# MINIO_OPTS="--address :9001 --console-address :9000"
# 修改为:
MINIO_OPTS="--address 127.0.0.1:9001 --console-address 127.0.0.1:9000"
保存文件 (Ctrl+X, Y, Enter)。
重启 MinIO 服务以应用更改:
sudo systemctl restart minio.service
创建Nginx配置文件
因为我们这俩都是MinIO的,我们就写到一个文件里面去
sudo nano /etc/nginx/sites-available/minio.conf
我们假定api域名为test1.com 控制台域名为test2.com
# /etc/nginx/sites-available/minio.conf
# --- MinIO API Server Block (test1.com) ---
server {
listen 80;
listen [::]:80;
server_name test1.com;
# 强制跳转到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name test1.com;
# SSL Certificate Configuration
ssl_certificate /etc/letsencrypt/live/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/privkey.pem;
# SSL Security Parameters (as provided)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s; # Google Public DNS, 确认服务器可访问
resolver_timeout 5s;
# Increase max body size for uploads (adjust as needed)
client_max_body_size 5G;
# Proxy API requests to MinIO API port (127.0.0.1:9001)
location / {
# Handle CORS preflight requests if necessary
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' always; # Consider restricting origin
add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, HEAD' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Content-Length, Host, X-Amz-Date, X-Amz-Content-Sha256, X-Amz-User-Agent' always;
add_header 'Access-Control-Max-Age' 1728000 always;
add_header 'Content-Type' 'text/plain charset=UTF-8' always;
add_header 'Content-Length' 0 always;
return 204;
}
proxy_set_header Host $http_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;
# Important for MinIO to know connection is secure
proxy_connect_timeout 300;
# Default is 60, increase if you have backend issues.
proxy_http_version 1.1; # Recommended for keepalive connections
proxy_set_header Connection ""; # Clear close connection from client
# Buffering can impact large uploads/downloads, consider off if issues arise
# proxy_buffering off;
# Ignore headers from client related to acceleration / caching
proxy_ignore_headers X-Accel-Redirect X-Accel-Buffering X-Accel-Limit-Rate X-Accel-Charset Expires Cache-Control Set-Cookie;
proxy_ignore_client_abort on;
proxy_pass http://127.0.0.1:9001;
}
}
# --- MinIO Console Server Block (test2.com) ---
server {
listen 80;
listen [::]:80;
server_name test2.com;
# 强制跳转到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name test2.com;
# SSL Certificate Configuration (Use the same certificate)
ssl_certificate /etc/letsencrypt/live/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/privkey.pem;
# SSL Security Parameters (Use the same parameters)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Proxy Console requests to MinIO Console port (127.0.0.1:9000)
location / {
proxy_set_header Host $http_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;
# Required for MinIO Console WebSocket functionality
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Consider turning off buffering for better Console responsiveness
# proxy_buffering off;
proxy_pass http://127.0.0.1:9000;
}
}
请注意修改里面的信息,SSL证书路径以及对应域名和端口
修改完后保存
创建符号链接
sudo ln -s /etc/nginx/sites-available/minio.conf /etc/nginx/sites-enabled/
(如果存在默认的 Nginx 配置链接 default
在 sites-enabled
中,你可能需要移除它:sudo rm /etc/nginx/sites-enabled/default
)
测试Nginx配置
sudo nginx -t
确保输出显示 syntax is ok
和 test is successful
。
重新加载Nginx
sudo systemctl reload nginx
这样之后去域名DNS解析一下就能用域名访问了
服务器防火墙配置
这里我推荐使用ufw (Uncomplicated Firewall) 是一个用户友好的 iptables/nftables 前端,在 Debian 上很常用
安装ufw
sudo apt update
sudo apt install ufw -y
检测ufw状态
sudo ufw status
初始状态应该是 "inactive"
设置默认策略
推荐设置默认拒绝所有传入连接,允许所有传出连接.
sudo ufw default deny incoming
sudo ufw default allow outgoing
允许必要的端口
SSH (端口 22): 允许你通过 SSH 连接到服务器。这一步非常重要,千万不要忘记! 如果你的 SSH 端口不是 22,请替换。
sudo ufw allow ssh
# 或者如果你确定是 22 端口
# sudo ufw allow 22/tcp
HTTP (端口 80): 允许 Nginx 接收 HTTP 请求。
sudo ufw allow http
# 或者
# sudo ufw allow 80/tcp
HTTPS (端口 443): 允许 Nginx 接收 HTTPS 请求
sudo ufw allow https
# 或者
# sudo ufw allow 443/tcp
启用防火墙
sudo ufw enable
系统可能会提示你此操作可能中断 SSH 连接,输入 y 并回车确认。
再次检查 ufw 状态:
sudo ufw status verbose
你应该能看到防火墙是 active 状态,并且允许了 ssh (或其他指定的端口), http, https。
如何删除某个端口
sudo ufw delete allow 端口/tcp
sudo ufw reload
如何卸载MinIO
先停掉进程
sudo systemctl stop minio
sudo systemctl disable minio
卸载 MinIO DEB 包
使用 dpkg
命令卸载 MinIO 软件包。
sudo dpkg -r minio
如果需要移除配置文件(通常不推荐,但如果想彻底干净,可以使用 --purge
):
# 谨慎使用 --purge,这会移除配置文件
# sudo dpkg --purge minio
移除 MinIO 数据目录
删除 MinIO 存储数据和配置的目录。请务必确认这是正确的目录,以免误删重要数据。在之前的文档中,我们使用了 /data/minio
。
sudo rm -rf /data/minio
(请将 /data/minio
替换为你实际使用的 MinIO 数据目录路径)
移除 MinIO 用户
删除为 MinIO 服务创建的系统用户。
sudo userdel minio-user
重新加载 Systemd 配置
在移除服务文件后,重新加载 Systemd 配置。
sudo systemctl daemon-reload