Arch Linux MinIO 部署与使用指南

Arch Linux MinIO 部署与使用指南

本文记录在 Arch Linux 云服务器上恢复 MinIO、配置开机运行,以及通过 Python 生成固件下载和日志上传预签名 URL 的完整过程。

示例公网 IP:203.0.113.10(文档示例专用地址,无法用于实际部署)。执行命令前,请统一替换为你自己的服务器公网 IP。本文中的用户名和密码均为示例或占位符。

1. 服务结构与注意事项

项目配置
S3 上传、下载接口http://203.0.113.10:9000
管理页面http://203.0.113.10:9001
固件 bucketfirmware
日志 bucketdiagnostic
数据目录/var/lib/minio/data
管理员配置/etc/minio/minio.env
服务配置/etc/systemd/system/minio.service

9000 是 S3 API,9001 是管理页面。浏览器访问 9000 根路径时出现 XML 或 AccessDenied,不表示服务故障。

MinIO 社区仓库于 2026 年 4 月 25 日归档,本文采用社区源码构建恢复既有服务。该方式不代表上游仍提供持续安全维护;长期运行应规划维护版本或迁移。参见 MinIO 社区仓库。

HTTP 不加密登录信息、文件和预签名链接。公网长期使用应配置 HTTPS;9001 建议仅允许管理员公网 IP 访问。预签名 URL 在有效期内可被持有者使用,不要公开传播。

本指南适用于新目录部署。如果旧数据盘仍存在,先备份、确认挂载与数据版本,勿覆盖原目录。重新安装服务不会恢复已经丢失的对象。

2. 安装工具

以下命令在服务器 SSH 终端执行,源码构建使用普通用户,仅安装和系统配置使用 sudo。

1
sudo pacman -Syu --needed base-devel git go python python-boto3 curl openssl nano

python-boto3 是 boto3 的 Arch 软件包,用于 Python 调用 S3 接口。MinIO 服务本身不依赖它,使用预签名 URL 的设备也无需安装。

3. 下载并构建 MinIO

1
2
3
4
5
mkdir -p ~/minio-build
cd ~/minio-build
git clone https://github.com/minio/minio.git
cd minio
git rev-parse HEAD | tee ../minio-source-commit.txt

如果 Git 自动将 GitHub 地址转换为失效代理,检查:

1
git config --show-origin --get-regexp 'url\..*\.insteadof'

若存在下述旧配置,可移除后重新克隆:

1
2
git config --global --unset-all \
'url.https://mirror.ghproxy.com/https://github.com/.insteadOf'

如果 Go 依赖下载缓慢,设置模块代理:

1
2
go env -w GOPROXY=https://goproxy.cn,direct
go env GOPROXY

如果提示环境变量覆盖配置,在当前终端执行:

1
export GOPROXY=https://goproxy.cn,direct

继续下载和编译:

1
2
3
4
5
cd ~/minio-build/minio
go mod download -x
go build -trimpath -o minio .
./minio --version
sudo install -m 0755 minio /usr/local/bin/minio

中断后可以重新执行,已下载的模块会复用,不要清理缓存。保留依赖校验,不要设置 GOSUMDB=off。若提示 Go 版本不足,升级至源码 go.mod 要求的版本。

4. 创建运行用户和目录

1
2
3
4
5
6
7
id minio >/dev/null 2>&1 || sudo useradd \
--system --user-group \
--home-dir /var/lib/minio \
--shell /usr/bin/nologin minio

sudo install -d -o minio -g minio -m 0750 /var/lib/minio/data
sudo install -d -o root -g root -m 0700 /etc/minio

如果使用独立数据盘,应先完成持久挂载,再调整数据路径及对应服务配置。

5. 设置管理员用户名和密码

1
sudo nano /etc/minio/minio.env

写入以下内容,把占位符替换为实际值,建议密码使用至少 24 位随机字母和数字:

1
2
3
MINIO_ROOT_USER=minio_admin
MINIO_ROOT_PASSWORD=REPLACE_WITH_A_NEW_RANDOM_PASSWORD
MINIO_REGION_NAME=us-east-1

可用下面的命令生成随机密码:

1
openssl rand -hex 24

在 nano 中按 Ctrl+O、回车保存,Ctrl+X 退出,然后设置权限:

1
sudo chmod 600 /etc/minio/minio.env

不要复用曾在聊天、截图或公开脚本中出现的旧密钥。

6. 配置 systemd 持久运行

以下配置按本次需求开放管理页面监听;安全组中应限制 9001 的访问来源。

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
sudo tee /etc/systemd/system/minio.service >/dev/null <<'EOF'
[Unit]
Description=MinIO Object Storage
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/var/lib/minio/data

[Service]
Type=simple
User=minio
Group=minio
EnvironmentFile=/etc/minio/minio.env
ExecStart=/usr/local/bin/minio server /var/lib/minio/data --address :9000 --console-address :9001
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/minio

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now minio
sudo systemctl status minio --no-pager

应显示 active (running)。验证健康状态和监听端口:

1
2
curl -i http://127.0.0.1:9000/minio/health/live
sudo ss -lntp | grep -E ':9000|:9001'

健康检查应返回 HTTP 200,正文可以为空。

修改管理员账号密码后,只需重启服务;修改 unit 文件后需要先执行 daemon-reload。更改管理员凭据后,使用旧凭据的脚本需要更新,旧凭据签发的链接也会失效。

7. 配置安全组和防火墙

在云平台安全组添加入站规则,保留现有 SSH 规则:

协议端口建议来源
TCP9000上传、下载设备所在网络;确需任意网络访问时再放宽
TCP9001管理员电脑公网 IP/32

检查本机使用的防火墙:

1
sudo systemctl is-active ufw firewalld nftables

只修改已经在使用的防火墙,不要同时启用多套。

如果使用 UFW,替换示例 IP 后执行:

1
2
3
sudo ufw allow 9000/tcp
sudo ufw allow from YOUR_ADMIN_PUBLIC_IP to any port 9001 proto tcp
sudo ufw status

如果使用自定义 nftables 或 firewalld,在现有配置中添加对应端口和来源规则并持久保存;不要清空现有规则。

从电脑浏览器访问:

  • 健康检查:http://203.0.113.10:9000/minio/health/live
  • 管理页面:http://203.0.113.10:9001/

管理页面使用第 5 步设置的账号密码。不同社区版本的管理界面功能可能不同,下面使用 boto3 创建 bucket,不依赖页面功能。

如果不需要公网管理页面,将服务中的 --console-address :9001 改为 --console-address 127.0.0.1:9001,关闭公网 9001,改用 SSH 转发:

1
2
# 在自己的电脑执行,替换 SSH 用户名
ssh -N -L 19001:127.0.0.1:9001 YOUR_SSH_USER@203.0.113.10

保持连接,浏览器打开 http://localhost:19001。

8. 配置 Python 凭据

以下命令在运行 Python 脚本的 Linux 机器执行;该机器需要安装 python-boto3。

1
2
3
4
5
6
7
/usr/bin/python -c "import boto3; print(boto3.__version__)"

export S3_ENDPOINT=http://203.0.113.10:9000
export AWS_ACCESS_KEY_ID=minio_admin
read -rsp "请输入 MinIO 管理员密码: " AWS_SECRET_ACCESS_KEY
echo
export AWS_SECRET_ACCESS_KEY

若使用其他用户名,替换 minio_admin。这些变量仅在当前终端有效,重新连接后需再次设置。不要把密钥硬编码进脚本或提交到代码仓库。

使用系统 Python 可以直接读取 pacman 安装的 boto3;默认虚拟环境无法读取系统包。若选择虚拟环境,需要单独在其中安装 boto3。

9. 创建私有 bucket

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
mkdir -p ~/minio-tools
cd ~/minio-tools

/usr/bin/python - <<'PY'
import os
import boto3
from botocore.config import Config
from botocore.exceptions import ClientError

s3 = boto3.client(
's3',
endpoint_url=os.environ['S3_ENDPOINT'],
region_name='us-east-1',
config=Config(signature_version='s3v4',
s3={'addressing_style': 'path'}),
)

for bucket in ('firmware', 'diagnostic'):
try:
s3.head_bucket(Bucket=bucket)
print(bucket, '已存在')
except ClientError as e:
if e.response['Error']['Code'] not in ('404', 'NoSuchBucket'):
raise
s3.create_bucket(Bucket=bucket)
print(bucket, '已创建')
PY

保持 bucket 私有,不需要开启匿名读写。

10. 上传固件到服务器

将以下内容保存为 ~/minio-tools/publish_firmware.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
import argparse
import os
import boto3
from botocore.config import Config

p = argparse.ArgumentParser()
p.add_argument('file', help='本地固件文件路径')
p.add_argument('key', help='bucket 内的对象路径')
a = p.parse_args()

s3 = boto3.client(
's3', endpoint_url=os.environ['S3_ENDPOINT'],
region_name='us-east-1',
config=Config(signature_version='s3v4',
s3={'addressing_style': 'path'}),
)
s3.upload_file(a.file, 'firmware', a.key)
print('上传完成:firmware/' + a.key)

示例:

1
2
cd ~/minio-tools
/usr/bin/python publish_firmware.py ./controller-v1.bin releases/controller-v1.bin

./controller-v1.bin 是本地文件;releases/controller-v1.bin 是远端对象名,无需预先创建目录。

11. 生成下载和上传预签名 URL

保存为 ~/minio-tools/presign.py:

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
#!/usr/bin/env python3
import argparse
import os
import boto3
from botocore.config import Config

p = argparse.ArgumentParser()
p.add_argument('action', choices=['download', 'upload'])
p.add_argument('key', help='对象路径')
p.add_argument('--expires', type=int, default=3600)
a = p.parse_args()
if not 1 <= a.expires <= 604800:
p.error('--expires 必须在 1 到 604800 秒之间')

s3 = boto3.client(
's3', endpoint_url=os.environ['S3_ENDPOINT'],
aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'],
aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'],
region_name='us-east-1',
config=Config(signature_version='s3v4',
s3={'addressing_style': 'path'}),
)
download = a.action == 'download'
print(s3.generate_presigned_url(
ClientMethod='get_object' if download else 'put_object',
Params={
'Bucket': 'firmware' if download else 'diagnostic',
'Key': a.key,
},
ExpiresIn=a.expires,
HttpMethod='GET' if download else 'PUT',
))

生成固件下载链接,默认有效期 1 小时:

1
/usr/bin/python presign.py download releases/controller-v1.bin

生成日志上传链接:

1
/usr/bin/python presign.py upload logs/device001/20261028-001.log

生成链接本身不上传文件,也不检查 bucket 和对象是否存在。必须使用客户端可达的地址签名,不能签名后再替换 URL 中的 IP、端口或路径。

旧脚本的 put_object 对应日志上传;固件下载使用 get_object。9001 不能作为脚本的 S3 endpoint。

12. 验证上传和下载

下载固件:

1
2
3
DOWNLOAD_URL=$(/usr/bin/python presign.py download releases/controller-v1.bin)
curl --fail --show-error -o downloaded.bin "$DOWNLOAD_URL"
sha256sum controller-v1.bin downloaded.bin

两个文件的 SHA-256 应一致。设备正式升级还应验证可信固件签名。

上传日志:

1
2
UPLOAD_URL=$(/usr/bin/python presign.py upload logs/device001/20261028-001.log)
curl --fail --show-error --upload-file ./device.log "$UPLOAD_URL"

上传使用 HTTP PUT,正文为原始文件内容,不是 multipart/form-data。URL 必须加引号,避免其中的 & 被终端解释。同名对象上传会覆盖原对象,建议对象名包含设备编号、时间和唯一编号。

可用管理员凭据查看上传结果:

1
2
3
4
5
6
7
8
9
10
11
/usr/bin/python - <<'PY'
import os
import boto3
from botocore.config import Config
s3 = boto3.client(
's3', endpoint_url=os.environ['S3_ENDPOINT'], region_name='us-east-1',
config=Config(signature_version='s3v4', s3={'addressing_style': 'path'}),
)
print(s3.head_object(Bucket='diagnostic',
Key='logs/device001/20261028-001.log')['ContentLength'])
PY

13. 日常使用的最小权限账号(建议)

前述步骤使用管理员凭据完成初始化。日常签发 URL 应使用专用账号,管理员凭据仅用于管理和发布固件。

如果需要通过命令行配置账号,构建社区客户端 mc:

1
2
3
4
5
6
cd ~/minio-build
git clone https://github.com/minio/mc.git
cd mc
git rev-parse HEAD | tee ../mc-source-commit.txt
go build -trimpath -o mc .
sudo install -m 0755 mc /usr/local/bin/mc

在服务器终端中,用第 8 步的管理员环境变量配置连接:

1
2
mc alias set local http://127.0.0.1:9000 \
"$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY"

mc 会保存管理凭据,请保护当前用户账号和 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
cd ~/minio-tools
cat > device-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::firmware/*"]
},
{
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": ["arn:aws:s3:::diagnostic/*"]
}
]
}
EOF

mc admin policy create local device-policy device-policy.json
DEVICE_SECRET=$(openssl rand -hex 32)
mc admin user add local device_signer "$DEVICE_SECRET"
mc admin policy attach local device-policy --user device_signer
printf '账号:device_signer\n密钥:%s\n' "$DEVICE_SECRET"
unset DEVICE_SECRET

将输出的新密钥存入密码管理器,然后将第 8 步的账号改为 device_signer,输入它的密钥,再运行 presign.py。该账号可下载固件、上传日志,但不能发布固件、删除对象或列出 bucket。

这个权限覆盖整个日志 bucket。若需要按设备隔离,应为每个设备或签发服务设置更窄的对象前缀和授权逻辑。密钥保存在签发端,设备只接收对应的预签名 URL。

14. 运行维护与故障排查

1
2
3
4
5
6
7
sudo systemctl status minio --no-pager
sudo systemctl restart minio
sudo journalctl -u minio -n 100 --no-pager
sudo journalctl -u minio -f
df -h /var/lib/minio/data
sudo timedatectl set-ntp true
timedatectl status
问题检查方法
ModuleNotFoundError: boto3安装 python-boto3,使用 /usr/bin/python;检查是否误用了虚拟环境
Go 依赖下载卡住配置 GOPROXY,运行 go mod download -x 查看具体请求
本机健康检查成功,公网超时云安全组、本机防火墙、实际公网 IP
管理页面打不开确认监听 :9001、安全组来源是否与当前电脑公网 IP 一致
9000 显示 XML 或 AccessDenied这是 S3 接口;管理页面在 9001
SignatureDoesNotMatch凭据、HTTP 方法、URL 是否被修改、额外签名请求头是否一致
AccessDenied签名账号权限、bucket、对象路径、链接是否过期
NoSuchKey固件未上传,或对象路径、大小写不一致
链接立即失效检查签发机器与服务器时间及凭据是否发生更改
服务无法启动查看 journalctl;检查配置、目录权限、磁盘挂载和端口占用

首次部署后可在维护窗口重启服务器,验证服务自动启动、健康检查正常且已有对象可读。

单机存储不等于备份。为数据、账号策略和服务配置安排异机备份;使用 S3 工具复制对象,或停服后做一致性磁盘备份,并验证恢复流程。不要手工修改运行中的 MinIO 数据目录。

15. 参考资料

本文根据本次恢复过程整理;具体服务器的命令执行结果以现场验证为准。