香港服务器搭建Minio对象存储:替代AWS S3的私有化文件存储 + CDN分发完整方案

香港服务器搭建Minio对象存储:替代AWS S3的私有化文件存储 + CDN分发完整方案

独立站用户上传的商品图片、用户头像、订单附件……这些文件放在哪里?放本地磁盘扩容麻烦,用 AWS S3 出口流量费昂贵,用阿里云 OSS 需要备案。在香港服务器上自托管 MinIO,获得完全兼容 S3 API 的对象存储,不仅成本比 S3 低 80%,数据也完全自主可控,结合 Cloudflare CDN 还能实现全球零出口流量费分发。


一、成本对比(1TB 数据,月均 1TB 流量)

方案存储费流量费月总费
AWS S3(标准)$23($0.023/GB)$90($0.09/GB)$113
Cloudflare R2$15($0.015/GB)$0(免费出口)$15
香港 VPS + MinIO(2TB盘)¥50~100(磁盘费用分摊)含在 VPS 套餐¥50~100

二、Docker 部署 MinIO

<code"># /opt/minio/docker-compose.yml
version: '3.8'

services:
  minio:
    image: minio/minio:latest
    container_name: minio
    restart: unless-stopped
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: your_access_key          # 相当于 S3 Access Key
      MINIO_ROOT_PASSWORD: your_secret_key_32+  # 相当于 S3 Secret Key(8位以上)
      MINIO_DOMAIN: storage.yourdomain.com      # 用于路径/虚拟主机样式 URL
      MINIO_BROWSER_REDIRECT_URL: https://minio-console.yourdomain.com
    ports:
      - "127.0.0.1:9000:9000"   # API 端口
      - "127.0.0.1:9001:9001"   # Web 控制台
    volumes:
      - /data/minio:/data       # 数据目录(建议挂载大容量磁盘)
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 10s
      retries: 3
<code"># 创建数据目录并启动
mkdir -p /data/minio
cd /opt/minio && docker compose up -d

# 访问 Web 控制台
# http://服务器IP:9001(通过 SSH 隧道访问,或配置 Nginx 反向代理)

三、Nginx 反向代理配置(API + 控制台)

<code"># MinIO API(S3 兼容接口)
server {
    listen 443 ssl http2;
    server_name storage.yourdomain.com;

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

    # 允许大文件上传
    client_max_body_size 5G;
    proxy_request_buffering off;   # 关闭请求缓冲(大文件流式上传)

    location / {
        proxy_pass http://127.0.0.1:9000;
        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;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;
    }
}

# MinIO Web 控制台
server {
    listen 443 ssl http2;
    server_name minio-console.yourdomain.com;

    # 限制只允许管理员 IP 访问控制台
    allow 你的IP;
    deny all;

    location / {
        proxy_pass http://127.0.0.1:9001;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
    }
}

四、Python 使用 MinIO(S3 兼容 SDK)

<code">import boto3
from botocore.config import Config

# 使用 boto3 连接 MinIO(S3 兼容,无需修改现有 S3 代码)
s3 = boto3.client(
    's3',
    endpoint_url='https://storage.yourdomain.com',
    aws_access_key_id='your_access_key',
    aws_secret_access_key='your_secret_key_32+',
    config=Config(signature_version='s3v4'),
    region_name='us-east-1'   # MinIO 不校验 region,填任意值即可
)

# ── 创建 Bucket ──
s3.create_bucket(Bucket='product-images')
s3.create_bucket(Bucket='user-uploads')

# ── 上传文件 ──
def upload_product_image(product_id: str, file_path: str, content_type: str = 'image/webp'):
    key = f"products/{product_id}/main.webp"
    with open(file_path, 'rb') as f:
        s3.put_object(
            Bucket='product-images',
            Key=key,
            Body=f,
            ContentType=content_type,
            CacheControl='public, max-age=31536000',  # 缓存1年
        )
    return f"https://storage.yourdomain.com/product-images/{key}"

# ── 生成预签名上传 URL(浏览器直接上传,不经过后端)──
def get_upload_url(file_name: str, content_type: str, expires: int = 3600):
    """
    生成预签名 URL,前端直接 PUT 上传到 MinIO
    避免文件经过后端服务器,减少后端带宽压力
    """
    key = f"uploads/{file_name}"
    url = s3.generate_presigned_url(
        'put_object',
        Params={
            'Bucket': 'user-uploads',
            'Key': key,
            'ContentType': content_type,
        },
        ExpiresIn=expires
    )
    return {"upload_url": url, "file_key": key}

# ── 设置 Bucket 公开读取策略 ──
import json

public_policy = {
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Principal": {"AWS": ["*"]},
        "Action": ["s3:GetObject"],
        "Resource": ["arn:aws:s3:::product-images/*"]
    }]
}
s3.put_bucket_policy(
    Bucket='product-images',
    Policy=json.dumps(public_policy)
)

五、Cloudflare CDN 加速 MinIO 文件

<code"># 在 Cloudflare 为 storage.yourdomain.com 添加 A 记录(开启橙色云朵代理)
# 这样文件通过 Cloudflare 全球 CDN 节点分发,出口流量免费

# Cloudflare 缓存规则(针对 MinIO 静态文件)
# 在 Cloudflare → Rules → Cache Rules 中添加:
# 匹配条件:Hostname = storage.yourdomain.com AND URI Path 包含 /product-images/
# 缓存动作:Cache Everything,Edge TTL = 1 Month

# 验证 CDN 缓存命中
curl -I https://storage.yourdomain.com/product-images/products/123/main.webp
# 查看响应头:CF-Cache-Status: HIT(表示从 CDN 节点返回)

六、自动化备份 MinIO 数据

<code"># 使用 MinIO Client(mc)将数据同步到 Cloudflare R2 作为备份
docker run --rm -it minio/mc alias set myminio https://storage.yourdomain.com your_access_key your_secret_key
docker run --rm -it minio/mc alias set r2 https://your-account.r2.cloudflarestorage.com R2_ACCESS_KEY R2_SECRET_KEY

# 每日凌晨 3 点将 product-images 同步到 R2 备份
echo "0 3 * * * docker run --rm minio/mc mirror myminio/product-images r2/backup-product-images --overwrite" >> /etc/crontab

七、总结

MinIO + Cloudflare CDN 是香港服务器对象存储的最优组合:存储成本比 AWS S3 低 80%+,CDN 分发零出口流量费,S3 兼容 API 让现有代码无需修改。适合商品图片、用户上传、静态资源等场景,数据完全自主可控。



Telegram