Duet G. Blog

Keep It Simple, Stupid

在家部署MinIO实现S3自由

这是一篇与随后准备写的部署Mastodon实例相关的文章。

S3是Simple Storage Service的缩写,是亚马逊提供的一种云存储模式,目前已是一种主流的云存储,大多数前端服务都支持S3接入,大多数的商业云存储服务也都兼容S3。

商业云存储目前大多数都是付费模式,个别限时或限量的免费体验版整体来说使用起来都不很自由。

借助开源软件的免费优势,我们今天来尝试在家庭服务器上部署自托管的MinIO对象存储服务。MinIO本身是兼容S3的,作为一种低成本解决方案,一旦部署好就可以基本替代商业云存储。要注意的是,低成本不代表无成本,基本替代也很难成为完美替代。

首先我们家中需要一台服务器(或者是服务器上的虚拟机)和一个域名。另外家庭宽带也需要公网IP,宽带上下行速度会直接影响文件传输速度。如果没有公网IP想用frp穿透的话,其数据传输速度自然会更加受影响,所以建议要有公网IP。后面会以安装好Docker的Debian/Ubuntu系统举例,当然你要用Podman也没问题。

先使用路由器的动态DNS(DDNS)功能把家庭宽带的公网IP自动更新到域名托管的DNS服务。然后再用路由器防火墙的端口映射功能把WAN口的9000端口映射到你服务器的9000端口。

然后再服务器里建立工作文件夹,并生成MinIO的配置文件

mkdir minio
cd minio
vim minioconfig

将如下内容按实际修改后粘贴进去。MinIO更多的环境变量可以参见这里

# MINIO_ROOT_USER 和 MINIO_ROOT_PASSWORD 设置 MinIO 服务器的 root 帐户。 
# 该用户拥有对部署中的任何资源执行 S3 和管理 API 操作的不受限制的权限。 
# 如将其备注掉不设置则使用默认值“minioadmin:minioadmin”。 
# MinIO 建议设置非默认值作为最佳实践,无论环境如何

MINIO_ROOT_USER=myminioadmin
MINIO_ROOT_PASSWORD=minio-secret-key-change-me

# MINIO_VOLUMES 设置用于 MinIO 服务器的存储卷或路径。

MINIO_VOLUMES="/mnt/data"

# MINIO_SERVER_URL 设置与 MinIO 服务器一起使用的本地计算机的主机名 
# MinIO 假设您的网络控制界面可以正确将此主机名解析到本地计算机 
# 取消注释以下行,并将该值替换为本地计算机的正确主机名和 MinIO 服务器的端口(默认为 9000)。
# 如https://你的域名:9000

#MINIO_SERVER_URL="https://minio.example.net:9000"

填入之后保存退出vim,之后来准备Docker Compose文件

vim docker-compose.yml

我们部署一个单节点单驱动的实例,进入编辑界面后把下面的内容按实际修改后填入

version: '2'

services:
  minio:
    container_name: minio
    command: server --console-address ":9090"
    environment:
      - MINIO_CONFIG_ENV_FILE=/etc/config.env
    image: quay.io/minio/minio:latest
    volumes:
      - ./data:/mnt/data
      - ./minioconfig:/etc/config.env
    restart: always
    ports:
      - "9001:9000"
      - "9090:9090"

这里设定工作文件夹下的data文件夹是整个存储的目录,你可以按需求把第11行冒号前面的./data修改成你想要的目录。或者你可以在工作目录下建立一个名为data的链接到你想要的目标目录。也可以用nfs协议把内网其他位置的硬盘目录映射到这个data上,总之按你的需要来处理存储位置的设置。同时为了后面使用NGINX来实现反向代理端口,容器的9000端口先映射到主机的9001端口了。

保存退出后就可以下载镜像生成容器了

docker compose up -d

容器顺利生成并启动后,我们来配置NGINX,首先设置站点配置文件

vim /etc/nginx/sites-available/minio

将下面的内容贴入编辑界面

server {
        listen 9000 ssl default_server;
        listen [::]:9000 ssl default_server;

        include snippets/snakeoil.conf;

        ssl_session_cache shared:le_nginx_SSL:10m;
        ssl_session_timeout 1440m;
        ssl_session_tickets off;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;

        ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

        server_name _;

        # To allow special characters in headers
        ignore_invalid_headers off;
        # Allow any size file to be uploaded.
        # Set to a value such as 1000m; to restrict file size to a specific value
        client_max_body_size 1000m;
        # To disable buffering
        proxy_buffering off;
        proxy_request_buffering off;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                # try_files $uri $uri/ =404;
                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;

                proxy_connect_timeout 300;
                # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
                proxy_http_version 1.1;
                proxy_set_header Connection "";
                chunked_transfer_encoding off;

                proxy_pass http://127.0.0.1:9001;
        }
}

这里我们假定了证书的储存位置是/etc/nginx/snippets/snakeoil.conf写的

ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

如果你希望是别的位置请修改相应的内容。保存退出后使用ln命令将其链接到enabled文件夹,并删掉其中的default配置

ln -s /etc/nginx/sites-available/minio /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default

然后我们使用acme.sh的DNS API功能来申请证书,使用DNS API申请证书不需要80端口,非常适合国内家庭宽带申请证书,而且acme.sh也支持大量的DNS服务商。具体的申请方法可参见这篇文章的前半部分。

证书设置完毕后就可以重启NGINX了,也可以先用nginx -t来检查一下配置是否正确。这里我只把MinIO的服务端口9000映射到了公网,而网页控制台的9090端口依然还在内网,从而确保服务的安全。如果你需要在外网访问的话可以考虑使用Tailscale之类的服务来远程访问这台主机的端口。

最后我们用这台服务器的内网IP加9090端口在浏览器上就可以访问MinIO的网页控制台,使用minioconfig中设置的用户名和密码登录即可。