diff --git a/backend/infrastructure/minio/.env.example b/backend/infrastructure/minio/.env.example new file mode 100644 index 00000000..b7fc2018 --- /dev/null +++ b/backend/infrastructure/minio/.env.example @@ -0,0 +1,102 @@ +# ============================================================================= +# MinIO Object Storage - 环境配置 +# ============================================================================= +# +# 部署位置: 与 Kong, Nginx 同一服务器 (Server A: 192.168.1.100) +# 用途: 用户头像、文档、资源文件的对象存储 +# +# 网络拓扑: +# ┌─────────────────────────────────────────────────────────────────────────────┐ +# │ Server A (192.168.1.100) - Gateway & Storage │ +# ├─────────────────────────────────────────────────────────────────────────────┤ +# │ Nginx :80/443 - 反向代理 (SSL 终止) │ +# │ Kong :8000 - API 网关 │ +# │ MinIO API :9000 - S3 兼容 API │ +# │ MinIO Console:9001 - Web 管理控制台 │ +# └─────────────────────────────────────────────────────────────────────────────┘ +# +# 设置步骤: +# 1. 复制配置: cp .env.example .env +# 2. 修改密码: 必须修改 MINIO_ROOT_PASSWORD +# 3. 创建数据目录: sudo mkdir -p /data/minio && sudo chown -R 1000:1000 /data/minio +# 4. 启动服务: ./deploy.sh up +# +# ============================================================================= + +# ============================================================================= +# MinIO 认证配置 +# ============================================================================= +# 管理员用户名 (至少 3 个字符) +MINIO_ROOT_USER=admin + +# 管理员密码 (至少 8 个字符) +# ⚠️ 安全警告: 生产环境必须修改此密码! +# 生成安全密码: openssl rand -base64 32 +MINIO_ROOT_PASSWORD=change_me_to_secure_password + +# ============================================================================= +# MinIO 服务端口 +# ============================================================================= +# S3 API 端口 - 应用程序通过此端口上传下载文件 +MINIO_API_PORT=9000 + +# Web 控制台端口 - 管理员通过此端口管理 MinIO +MINIO_CONSOLE_PORT=9001 + +# ============================================================================= +# MinIO 服务器配置 +# ============================================================================= +# 区域设置 (用于 S3 兼容性) +MINIO_REGION=cn-east-1 + +# 控制台外部访问 URL (用于 Nginx 反向代理场景) +# 内网访问: http://192.168.1.100:9001 +# 外网访问: https://minio.szaiai.com +MINIO_CONSOLE_URL=http://localhost:9001 + +# ============================================================================= +# 数据存储配置 +# ============================================================================= +# 数据存储路径 (确保有足够的磁盘空间) +# 建议使用独立的数据盘 +MINIO_DATA_PATH=/data/minio + +# ============================================================================= +# 默认存储桶配置 +# ============================================================================= +# 用户头像存储桶 (公开读取) +BUCKET_AVATARS=avatars + +# 用户文档存储桶 (需要认证) +BUCKET_DOCUMENTS=documents + +# 应用资源文件存储桶 (公开读取) +BUCKET_RESOURCES=resources + +# 备份文件存储桶 (私有) +BUCKET_BACKUPS=backups + +# ============================================================================= +# 服务间通信配置 (供后端服务使用) +# ============================================================================= +# MinIO 内部端点 (后端服务访问) +# 在同一服务器: http://localhost:9000 +# 在不同服务器: http://192.168.1.100:9000 +MINIO_ENDPOINT=http://localhost:9000 + +# 公开访问 URL (前端直接访问静态资源) +# 通过 Nginx 代理: https://cdn.szaiai.com +# 直接访问: http://192.168.1.100:9000 +MINIO_PUBLIC_URL=http://localhost:9000 + +# ============================================================================= +# 网络配置 +# ============================================================================= +# 本机 IP (供其他服务连接) +MINIO_HOST_IP=192.168.1.100 + +# ============================================================================= +# 日志配置 +# ============================================================================= +# 日志级别: DEBUG, INFO, WARNING, ERROR +MINIO_LOG_LEVEL=INFO diff --git a/backend/infrastructure/minio/README.md b/backend/infrastructure/minio/README.md new file mode 100644 index 00000000..2aa4d00c --- /dev/null +++ b/backend/infrastructure/minio/README.md @@ -0,0 +1,244 @@ +# MinIO 对象存储服务 + +MinIO 是一个高性能的分布式对象存储系统,兼容 Amazon S3 API。本配置用于存储用户头像、文档、资源文件等。 + +## 架构 + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Server A (192.168.1.100) - Gateway & Storage │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────────┐ │ +│ │ Nginx │────▶│ MinIO │────▶│ /data/minio (Volume) │ │ +│ │ :80/:443 │ │ :9000/9001 │ │ │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ Kong │ │ Buckets: │ │ +│ │ :8000 │ │ - avatars │ │ +│ └─────────────┘ │ - documents│ │ +│ │ - resources│ │ +│ │ - backups │ │ +│ └─────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +## 快速开始 + +### 1. 配置环境变量 + +```bash +cd backend/infrastructure/minio +cp .env.example .env + +# 编辑 .env 文件,修改以下必要配置 +vim .env + +# 必须修改的配置: +# MINIO_ROOT_PASSWORD=your_secure_password +``` + +### 2. 创建数据目录 + +```bash +sudo mkdir -p /data/minio +sudo chown -R 1000:1000 /data/minio +``` + +### 3. 启动服务 + +```bash +./deploy.sh up +``` + +### 4. 验证服务 + +```bash +# 查看状态 +./deploy.sh status + +# 健康检查 +./deploy.sh health + +# 列出存储桶 +./deploy.sh list-buckets +``` + +## 部署脚本命令 + +| 命令 | 说明 | +|------|------| +| `./deploy.sh up` | 启动 MinIO | +| `./deploy.sh down` | 停止 MinIO | +| `./deploy.sh restart` | 重启 MinIO | +| `./deploy.sh logs` | 查看日志 | +| `./deploy.sh logs -f` | 实时查看日志 | +| `./deploy.sh status` | 查看运行状态 | +| `./deploy.sh health` | 健康检查 | +| `./deploy.sh create-bucket ` | 创建存储桶 | +| `./deploy.sh list-buckets` | 列出所有存储桶 | +| `./deploy.sh info` | 查看服务器信息 | +| `./deploy.sh backup` | 备份配置 | + +## 访问地址 + +| 服务 | 地址 | 说明 | +|------|------|------| +| S3 API | http://localhost:9000 | 应用程序访问 | +| Web Console | http://localhost:9001 | 管理界面 | + +## 默认存储桶 + +| 存储桶 | 访问策略 | 用途 | +|--------|----------|------| +| `avatars` | 公开读取 | 用户头像 | +| `documents` | 私有 | 用户文档 | +| `resources` | 公开读取 | 应用资源 | +| `backups` | 私有 | 备份文件 | + +## Nginx 配置 + +### 安装 Nginx 反向代理 + +```bash +cd nginx +sudo ./install.sh + +# 配置 SSL +sudo ./install.sh --ssl +``` + +### 域名配置 + +| 域名 | 用途 | +|------|------| +| `minio.szaiai.com` | MinIO S3 API | +| `console.minio.szaiai.com` | MinIO 管理控制台 | +| `cdn.szaiai.com` | 静态资源 CDN | + +## 后端服务集成 + +### NestJS 集成示例 + +```typescript +// minio.config.ts +import { registerAs } from '@nestjs/config'; + +export default registerAs('minio', () => ({ + endPoint: process.env.MINIO_ENDPOINT || 'localhost', + port: parseInt(process.env.MINIO_PORT, 10) || 9000, + useSSL: process.env.MINIO_USE_SSL === 'true', + accessKey: process.env.MINIO_ACCESS_KEY, + secretKey: process.env.MINIO_SECRET_KEY, + buckets: { + avatars: process.env.MINIO_BUCKET_AVATARS || 'avatars', + documents: process.env.MINIO_BUCKET_DOCUMENTS || 'documents', + }, +})); +``` + +```typescript +// minio.service.ts +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import * as Minio from 'minio'; + +@Injectable() +export class MinioService { + private client: Minio.Client; + + constructor(private configService: ConfigService) { + this.client = new Minio.Client({ + endPoint: this.configService.get('minio.endPoint'), + port: this.configService.get('minio.port'), + useSSL: this.configService.get('minio.useSSL'), + accessKey: this.configService.get('minio.accessKey'), + secretKey: this.configService.get('minio.secretKey'), + }); + } + + async uploadAvatar(userId: string, file: Buffer, contentType: string): Promise { + const bucket = this.configService.get('minio.buckets.avatars'); + const objectName = `${userId}/${Date.now()}.${this.getExtension(contentType)}`; + + await this.client.putObject(bucket, objectName, file, { + 'Content-Type': contentType, + }); + + return `${bucket}/${objectName}`; + } + + getPublicUrl(objectPath: string): string { + const publicUrl = this.configService.get('minio.publicUrl'); + return `${publicUrl}/${objectPath}`; + } +} +``` + +### 环境变量配置 + +在后端服务的 `.env` 中添加: + +```env +# MinIO Configuration +MINIO_ENDPOINT=192.168.1.100 +MINIO_PORT=9000 +MINIO_USE_SSL=false +MINIO_ACCESS_KEY=admin +MINIO_SECRET_KEY=your_minio_password +MINIO_BUCKET_AVATARS=avatars +MINIO_BUCKET_DOCUMENTS=documents +MINIO_PUBLIC_URL=https://cdn.szaiai.com +``` + +## 安全建议 + +1. **修改默认密码**: 生产环境必须修改 `MINIO_ROOT_PASSWORD` +2. **网络隔离**: MinIO 端口应仅对内网开放 +3. **访问控制**: 使用 IAM 策略控制存储桶访问 +4. **SSL 加密**: 生产环境启用 HTTPS +5. **定期备份**: 配置数据备份策略 + +## 监控 + +MinIO 提供 Prometheus 格式的指标: + +``` +http://localhost:9000/minio/v2/metrics/cluster +``` + +可在 Grafana 中添加 MinIO Dashboard (ID: 13502)。 + +## 故障排除 + +### MinIO 无法启动 + +```bash +# 检查日志 +./deploy.sh logs + +# 检查数据目录权限 +ls -la /data/minio +``` + +### 无法连接 + +```bash +# 检查端口 +netstat -tlnp | grep 9000 + +# 检查防火墙 +sudo ufw status +``` + +### 上传失败 + +```bash +# 检查存储桶是否存在 +./deploy.sh list-buckets + +# 检查磁盘空间 +df -h /data/minio +``` diff --git a/backend/infrastructure/minio/deploy.sh b/backend/infrastructure/minio/deploy.sh new file mode 100644 index 00000000..ba1133df --- /dev/null +++ b/backend/infrastructure/minio/deploy.sh @@ -0,0 +1,367 @@ +#!/bin/bash +# ============================================================================= +# MinIO Object Storage - 部署脚本 +# ============================================================================= +# +# 用法: +# ./deploy.sh up 启动 MinIO +# ./deploy.sh down 停止 MinIO +# ./deploy.sh restart 重启 MinIO +# ./deploy.sh logs 查看日志 +# ./deploy.sh status 查看状态 +# ./deploy.sh health 健康检查 +# ./deploy.sh create-bucket 创建存储桶 +# ./deploy.sh list-buckets 列出所有存储桶 +# ./deploy.sh info 查看服务器信息 +# ./deploy.sh backup 备份配置 +# +# 示例: +# ./deploy.sh up # 启动 MinIO +# ./deploy.sh create-bucket uploads # 创建 uploads 存储桶 +# ./deploy.sh logs -f # 实时查看日志 +# +# ============================================================================= + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# 配置 +COMPOSE_FILE="docker-compose.yml" +ENV_FILE=".env" +ENV_EXAMPLE=".env.example" + +# ============================================================================= +# 工具函数 +# ============================================================================= + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_step() { + echo -e "${CYAN}[STEP]${NC} $1" +} + +# 检查 .env 文件 +check_env() { + if [ ! -f "$ENV_FILE" ]; then + if [ -f "$ENV_EXAMPLE" ]; then + log_info "创建 .env 文件..." + cp "$ENV_EXAMPLE" "$ENV_FILE" + log_warning "请检查 .env 文件并配置必要的环境变量" + log_warning "特别注意: MINIO_ROOT_PASSWORD 必须修改为安全密码" + else + log_error ".env.example 文件不存在" + exit 1 + fi + fi + + # 加载环境变量 + if [ -f "$ENV_FILE" ]; then + export $(grep -v '^#' "$ENV_FILE" | xargs) + fi +} + +# 检查数据目录 +check_data_dir() { + local data_path="${MINIO_DATA_PATH:-/data/minio}" + if [ ! -d "$data_path" ]; then + log_info "创建数据目录: $data_path" + sudo mkdir -p "$data_path" + sudo chown -R 1000:1000 "$data_path" + log_success "数据目录已创建" + fi +} + +# 获取 MinIO 连接信息 +get_minio_endpoint() { + echo "http://localhost:${MINIO_API_PORT:-9000}" +} + +# 配置 mc 客户端 +setup_mc() { + local endpoint=$(get_minio_endpoint) + local user="${MINIO_ROOT_USER:-admin}" + local password="${MINIO_ROOT_PASSWORD:-minio_secret_password}" + + if command -v mc &> /dev/null; then + mc alias set rwa "$endpoint" "$user" "$password" --api S3v4 > /dev/null 2>&1 + return 0 + else + # 使用 docker 中的 mc + docker exec rwa-minio mc alias set local http://localhost:9000 "$user" "$password" --api S3v4 > /dev/null 2>&1 + return 0 + fi +} + +# ============================================================================= +# 命令实现 +# ============================================================================= + +cmd_up() { + check_env + check_data_dir + + log_info "启动 MinIO 对象存储..." + docker compose -f "$COMPOSE_FILE" up -d + + log_info "等待服务启动..." + sleep 5 + + log_success "MinIO 已启动!" + echo "" + cmd_status +} + +cmd_down() { + log_info "停止 MinIO..." + docker compose -f "$COMPOSE_FILE" down + log_success "MinIO 已停止" +} + +cmd_restart() { + log_info "重启 MinIO..." + docker compose -f "$COMPOSE_FILE" restart minio + log_success "MinIO 已重启" +} + +cmd_logs() { + docker compose -f "$COMPOSE_FILE" logs "$@" minio +} + +cmd_status() { + echo "" + echo "==========================================" + echo " MinIO Object Storage 状态" + echo "==========================================" + echo "" + + docker compose -f "$COMPOSE_FILE" ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" + + echo "" + echo "==========================================" + echo " 访问地址" + echo "==========================================" + echo "" + echo " S3 API: http://localhost:${MINIO_API_PORT:-9000}" + echo " Console: http://localhost:${MINIO_CONSOLE_PORT:-9001}" + echo "" + echo " 默认凭证:" + echo " 用户名: ${MINIO_ROOT_USER:-admin}" + echo " 密码: (见 .env 文件)" + echo "" +} + +cmd_health() { + echo "" + echo "==========================================" + echo " MinIO 健康检查" + echo "==========================================" + echo "" + + local endpoint=$(get_minio_endpoint) + + # 检查 API 端点 + if curl -s "${endpoint}/minio/health/live" > /dev/null 2>&1; then + echo -e " API Health: ${GREEN}✓ Live${NC}" + else + echo -e " API Health: ${RED}✗ Not responding${NC}" + fi + + # 检查就绪状态 + if curl -s "${endpoint}/minio/health/ready" > /dev/null 2>&1; then + echo -e " Ready Status: ${GREEN}✓ Ready${NC}" + else + echo -e " Ready Status: ${RED}✗ Not ready${NC}" + fi + + # 检查集群状态 + if curl -s "${endpoint}/minio/health/cluster" > /dev/null 2>&1; then + echo -e " Cluster: ${GREEN}✓ Healthy${NC}" + else + echo -e " Cluster: ${YELLOW}○ Standalone mode${NC}" + fi + + echo "" +} + +cmd_create_bucket() { + local bucket_name="$1" + if [ -z "$bucket_name" ]; then + log_error "请提供存储桶名称" + echo "用法: $0 create-bucket " + exit 1 + fi + + check_env + setup_mc + + log_info "创建存储桶: $bucket_name" + + if command -v mc &> /dev/null; then + mc mb --ignore-existing "rwa/$bucket_name" + else + docker exec rwa-minio mc mb --ignore-existing "local/$bucket_name" + fi + + log_success "存储桶 '$bucket_name' 已创建" +} + +cmd_list_buckets() { + check_env + setup_mc + + echo "" + echo "==========================================" + echo " MinIO 存储桶列表" + echo "==========================================" + echo "" + + if command -v mc &> /dev/null; then + mc ls rwa + else + docker exec rwa-minio mc ls local + fi + + echo "" +} + +cmd_info() { + check_env + setup_mc + + echo "" + echo "==========================================" + echo " MinIO 服务器信息" + echo "==========================================" + echo "" + + if command -v mc &> /dev/null; then + mc admin info rwa + else + docker exec rwa-minio mc admin info local + fi + + echo "" +} + +cmd_backup() { + check_env + local backup_dir="${SCRIPT_DIR}/backups" + local timestamp=$(date +"%Y%m%d_%H%M%S") + local backup_file="${backup_dir}/minio_config_${timestamp}.tar.gz" + + mkdir -p "$backup_dir" + + log_info "备份 MinIO 配置..." + + # 备份 .env 和 docker-compose 配置 + tar -czf "$backup_file" \ + -C "$SCRIPT_DIR" \ + .env docker-compose.yml 2>/dev/null || true + + log_success "配置已备份到: $backup_file" +} + +cmd_help() { + echo "" + echo "MinIO Object Storage 部署工具" + echo "" + echo "用法: $0 <命令> [参数...]" + echo "" + echo "命令:" + echo " up 启动 MinIO" + echo " down 停止 MinIO" + echo " restart 重启 MinIO" + echo " logs [options] 查看日志 (支持 -f 参数)" + echo " status 查看运行状态" + echo " health 健康检查" + echo " create-bucket 创建存储桶" + echo " list-buckets 列出所有存储桶" + echo " info 查看服务器信息" + echo " backup 备份配置" + echo " help 显示帮助" + echo "" + echo "示例:" + echo " $0 up # 启动 MinIO" + echo " $0 logs -f # 实时查看日志" + echo " $0 create-bucket uploads # 创建 uploads 存储桶" + echo " $0 list-buckets # 列出所有存储桶" + echo "" + echo "环境变量 (可在 .env 中配置):" + echo " MINIO_ROOT_USER 管理员用户名 (默认: admin)" + echo " MINIO_ROOT_PASSWORD 管理员密码" + echo " MINIO_API_PORT S3 API 端口 (默认: 9000)" + echo " MINIO_CONSOLE_PORT Web 控制台端口 (默认: 9001)" + echo " MINIO_DATA_PATH 数据存储路径 (默认: /data/minio)" + echo "" +} + +# ============================================================================= +# 主入口 +# ============================================================================= + +case "${1:-help}" in + up) + cmd_up + ;; + down) + cmd_down + ;; + restart) + cmd_restart + ;; + logs) + shift + cmd_logs "$@" + ;; + status) + cmd_status + ;; + health) + cmd_health + ;; + create-bucket) + shift + cmd_create_bucket "$@" + ;; + list-buckets) + cmd_list_buckets + ;; + info) + cmd_info + ;; + backup) + cmd_backup + ;; + help|--help|-h) + cmd_help + ;; + *) + log_error "未知命令: $1" + cmd_help + exit 1 + ;; +esac diff --git a/backend/infrastructure/minio/docker-compose.yml b/backend/infrastructure/minio/docker-compose.yml new file mode 100644 index 00000000..f721df9f --- /dev/null +++ b/backend/infrastructure/minio/docker-compose.yml @@ -0,0 +1,124 @@ +# ============================================================================= +# MinIO Object Storage - Docker Compose +# ============================================================================= +# +# MinIO 是一个高性能的分布式对象存储系统,兼容 Amazon S3 API +# +# 用途: +# - 用户头像存储 +# - 用户文档存储 +# - 应用资源文件存储 +# - 备份文件存储 +# +# 使用方法: +# ./deploy.sh up # 启动 MinIO +# ./deploy.sh down # 停止 MinIO +# ./deploy.sh status # 查看状态 +# ./deploy.sh logs # 查看日志 +# ./deploy.sh create-bucket # 创建存储桶 +# +# 访问地址: +# API: http://localhost:9000 +# Console: http://localhost:9001 +# +# ============================================================================= + +services: + # =========================================================================== + # MinIO Object Storage + # =========================================================================== + minio: + image: docker.io/minio/minio:RELEASE.2024-11-07T00-52-20Z + container_name: rwa-minio + command: server /data --console-address ":9001" + environment: + # 管理员凭证 + MINIO_ROOT_USER: ${MINIO_ROOT_USER:-admin} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minio_secret_password} + # 服务器配置 + MINIO_BROWSER: "on" + MINIO_BROWSER_REDIRECT_URL: ${MINIO_CONSOLE_URL:-http://localhost:9001} + # 区域设置 + MINIO_REGION: ${MINIO_REGION:-cn-east-1} + # 性能优化 + MINIO_API_REQUESTS_DEADLINE: 10s + MINIO_API_REQUESTS_MAX: 10000 + ports: + - "${MINIO_API_PORT:-9000}:9000" # S3 API + - "${MINIO_CONSOLE_PORT:-9001}:9001" # Web Console + volumes: + - minio_data:/data + healthcheck: + test: ["CMD", "mc", "ready", "local"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + restart: unless-stopped + networks: + - rwa-minio + + # =========================================================================== + # MinIO Client (mc) - 初始化配置 + # =========================================================================== + # 用于创建默认存储桶和配置访问策略 + # =========================================================================== + minio-init: + image: docker.io/minio/mc:RELEASE.2024-11-05T11-29-45Z + container_name: rwa-minio-init + depends_on: + minio: + condition: service_healthy + environment: + MINIO_ROOT_USER: ${MINIO_ROOT_USER:-admin} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minio_secret_password} + # 存储桶配置 + BUCKET_AVATARS: ${BUCKET_AVATARS:-avatars} + BUCKET_DOCUMENTS: ${BUCKET_DOCUMENTS:-documents} + BUCKET_RESOURCES: ${BUCKET_RESOURCES:-resources} + BUCKET_BACKUPS: ${BUCKET_BACKUPS:-backups} + entrypoint: > + /bin/sh -c " + echo 'Waiting for MinIO to be ready...'; + sleep 5; + + echo 'Configuring MinIO client...'; + mc alias set rwa http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}; + + echo 'Creating buckets...'; + mc mb --ignore-existing rwa/$${BUCKET_AVATARS}; + mc mb --ignore-existing rwa/$${BUCKET_DOCUMENTS}; + mc mb --ignore-existing rwa/$${BUCKET_RESOURCES}; + mc mb --ignore-existing rwa/$${BUCKET_BACKUPS}; + + echo 'Setting bucket policies...'; + mc anonymous set download rwa/$${BUCKET_AVATARS}; + mc anonymous set download rwa/$${BUCKET_RESOURCES}; + + echo 'Setting lifecycle rules for avatars (keep versions for 30 days)...'; + mc ilm rule add --noncurrent-expire-days 30 rwa/$${BUCKET_AVATARS} || true; + + echo 'MinIO initialization complete!'; + mc admin info rwa; + " + networks: + - rwa-minio + +# ============================================================================= +# Volumes - 持久化存储 +# ============================================================================= +volumes: + minio_data: + driver: local + driver_opts: + type: none + o: bind + device: ${MINIO_DATA_PATH:-/data/minio} + +# ============================================================================= +# Networks +# ============================================================================= +networks: + rwa-minio: + driver: bridge + name: rwa-minio diff --git a/backend/infrastructure/minio/nginx/install.sh b/backend/infrastructure/minio/nginx/install.sh new file mode 100644 index 00000000..4d82bbcd --- /dev/null +++ b/backend/infrastructure/minio/nginx/install.sh @@ -0,0 +1,190 @@ +#!/bin/bash +# ============================================================================= +# MinIO Nginx 配置安装脚本 +# ============================================================================= +# +# 功能: +# - 安装 MinIO Nginx 反向代理配置 +# - 配置 SSL 证书 (可选) +# - 创建缓存目录 +# +# 用法: +# ./install.sh # 安装配置 +# ./install.sh --ssl # 安装配置并配置 SSL +# ./install.sh --uninstall # 卸载配置 +# +# ============================================================================= + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +NGINX_AVAILABLE="/etc/nginx/sites-available" +NGINX_ENABLED="/etc/nginx/sites-enabled" +CONFIG_FILE="minio.szaiai.com.conf" + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 检查 root 权限 +check_root() { + if [ "$EUID" -ne 0 ]; then + log_error "请使用 root 权限运行此脚本" + echo "用法: sudo $0" + exit 1 + fi +} + +# 安装配置 +install_config() { + check_root + + log_info "安装 MinIO Nginx 配置..." + + # 检查 Nginx 是否安装 + if ! command -v nginx &> /dev/null; then + log_error "Nginx 未安装,请先安装 Nginx" + exit 1 + fi + + # 创建缓存目录 + log_info "创建缓存目录..." + mkdir -p /var/cache/nginx/minio + chown -R www-data:www-data /var/cache/nginx/minio + + # 复制配置文件 + log_info "复制配置文件..." + cp "$SCRIPT_DIR/$CONFIG_FILE" "$NGINX_AVAILABLE/" + + # 创建符号链接 + if [ -L "$NGINX_ENABLED/$CONFIG_FILE" ]; then + log_warning "配置已存在,正在更新..." + rm "$NGINX_ENABLED/$CONFIG_FILE" + fi + ln -s "$NGINX_AVAILABLE/$CONFIG_FILE" "$NGINX_ENABLED/" + + # 测试配置 + log_info "测试 Nginx 配置..." + if nginx -t; then + log_success "配置测试通过" + else + log_error "配置测试失败,请检查配置文件" + exit 1 + fi + + # 重新加载 Nginx + log_info "重新加载 Nginx..." + systemctl reload nginx + + log_success "MinIO Nginx 配置安装完成!" + echo "" + echo "下一步:" + echo " 1. 确保 DNS 已配置指向此服务器" + echo " 2. 运行 ./install.sh --ssl 配置 SSL 证书" + echo "" +} + +# 配置 SSL +setup_ssl() { + check_root + + log_info "配置 SSL 证书..." + + # 检查 certbot + if ! command -v certbot &> /dev/null; then + log_info "安装 certbot..." + apt-get update + apt-get install -y certbot python3-certbot-nginx + fi + + log_info "获取 SSL 证书..." + certbot --nginx \ + -d minio.szaiai.com \ + -d console.minio.szaiai.com \ + -d cdn.szaiai.com \ + --non-interactive \ + --agree-tos \ + --email admin@szaiai.com \ + --redirect + + log_success "SSL 证书配置完成!" +} + +# 卸载配置 +uninstall_config() { + check_root + + log_info "卸载 MinIO Nginx 配置..." + + # 删除符号链接 + if [ -L "$NGINX_ENABLED/$CONFIG_FILE" ]; then + rm "$NGINX_ENABLED/$CONFIG_FILE" + log_info "已删除启用的配置" + fi + + # 删除配置文件 + if [ -f "$NGINX_AVAILABLE/$CONFIG_FILE" ]; then + rm "$NGINX_AVAILABLE/$CONFIG_FILE" + log_info "已删除配置文件" + fi + + # 重新加载 Nginx + systemctl reload nginx + + log_success "MinIO Nginx 配置已卸载" +} + +# 显示帮助 +show_help() { + echo "" + echo "MinIO Nginx 配置安装脚本" + echo "" + echo "用法: $0 [选项]" + echo "" + echo "选项:" + echo " (无参数) 安装 Nginx 配置" + echo " --ssl 配置 SSL 证书 (需要先安装配置)" + echo " --uninstall 卸载配置" + echo " --help 显示帮助" + echo "" +} + +# 主入口 +case "${1:-}" in + --ssl) + setup_ssl + ;; + --uninstall) + uninstall_config + ;; + --help|-h) + show_help + ;; + "") + install_config + ;; + *) + log_error "未知选项: $1" + show_help + exit 1 + ;; +esac diff --git a/backend/infrastructure/minio/nginx/minio.szaiai.com.conf b/backend/infrastructure/minio/nginx/minio.szaiai.com.conf new file mode 100644 index 00000000..8a9b00fc --- /dev/null +++ b/backend/infrastructure/minio/nginx/minio.szaiai.com.conf @@ -0,0 +1,229 @@ +# ============================================================================= +# MinIO Nginx 配置 +# ============================================================================= +# +# 功能: +# - MinIO API 反向代理 (S3 兼容) +# - MinIO Console 反向代理 +# - SSL/TLS 终止 +# - 静态资源 CDN 缓存 +# +# 安装: +# sudo cp minio.szaiai.com.conf /etc/nginx/sites-available/ +# sudo ln -s /etc/nginx/sites-available/minio.szaiai.com.conf /etc/nginx/sites-enabled/ +# sudo nginx -t && sudo systemctl reload nginx +# +# SSL 证书 (使用 certbot): +# sudo certbot --nginx -d minio.szaiai.com -d cdn.szaiai.com +# +# ============================================================================= + +# 上游服务器定义 +upstream minio_api { + server 127.0.0.1:9000; + keepalive 32; +} + +upstream minio_console { + server 127.0.0.1:9001; + keepalive 32; +} + +# ============================================================================= +# MinIO API (S3 兼容) - minio.szaiai.com +# ============================================================================= +server { + listen 80; + listen [::]:80; + server_name minio.szaiai.com; + + # 强制 HTTPS + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name minio.szaiai.com; + + # SSL 配置 (由 certbot 管理) + ssl_certificate /etc/letsencrypt/live/minio.szaiai.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/minio.szaiai.com/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + # 日志 + access_log /var/log/nginx/minio.szaiai.com.access.log; + error_log /var/log/nginx/minio.szaiai.com.error.log; + + # 客户端配置 + client_max_body_size 100M; + client_body_buffer_size 128k; + client_body_timeout 300s; + + # 代理缓冲配置 + proxy_buffering off; + proxy_request_buffering off; + + # MinIO API 代理 + location / { + proxy_pass http://minio_api; + proxy_http_version 1.1; + + # 保持连接 + proxy_set_header Connection ""; + + # 必要的头部 + 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; + + # S3 特定头部 + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # 超时配置 + proxy_connect_timeout 60s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + + # WebSocket 支持 (用于控制台实时日志) + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} + +# ============================================================================= +# MinIO Console - console.minio.szaiai.com +# ============================================================================= +server { + listen 80; + listen [::]:80; + server_name console.minio.szaiai.com; + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name console.minio.szaiai.com; + + # SSL 配置 + ssl_certificate /etc/letsencrypt/live/minio.szaiai.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/minio.szaiai.com/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + # 日志 + access_log /var/log/nginx/console.minio.access.log; + error_log /var/log/nginx/console.minio.error.log; + + # MinIO Console 代理 + location / { + proxy_pass http://minio_console; + proxy_http_version 1.1; + + 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 支持 (Console 实时功能) + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # 超时配置 + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } +} + +# ============================================================================= +# CDN 静态资源 - cdn.szaiai.com +# ============================================================================= +# 用于公开访问的静态资源 (头像、资源文件等) +# ============================================================================= +server { + listen 80; + listen [::]:80; + server_name cdn.szaiai.com; + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name cdn.szaiai.com; + + # SSL 配置 + ssl_certificate /etc/letsencrypt/live/cdn.szaiai.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cdn.szaiai.com/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + # 日志 + access_log /var/log/nginx/cdn.szaiai.com.access.log; + error_log /var/log/nginx/cdn.szaiai.com.error.log; + + # 缓存配置 + proxy_cache_path /var/cache/nginx/minio levels=1:2 keys_zone=minio_cache:100m max_size=10g inactive=7d use_temp_path=off; + + # 公开存储桶 - avatars + location /avatars/ { + proxy_pass http://minio_api/avatars/; + proxy_http_version 1.1; + proxy_set_header Connection ""; + + # 缓存配置 + proxy_cache minio_cache; + proxy_cache_valid 200 7d; + proxy_cache_valid 404 1m; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_lock on; + + # 缓存头部 + add_header X-Cache-Status $upstream_cache_status; + add_header Cache-Control "public, max-age=604800"; + + # CORS 配置 + add_header Access-Control-Allow-Origin "*"; + add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS"; + } + + # 公开存储桶 - resources + location /resources/ { + proxy_pass http://minio_api/resources/; + proxy_http_version 1.1; + proxy_set_header Connection ""; + + # 缓存配置 + proxy_cache minio_cache; + proxy_cache_valid 200 7d; + proxy_cache_valid 404 1m; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_lock on; + + # 缓存头部 + add_header X-Cache-Status $upstream_cache_status; + add_header Cache-Control "public, max-age=604800"; + + # CORS 配置 + add_header Access-Control-Allow-Origin "*"; + add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS"; + } + + # 默认拒绝其他路径 + location / { + return 403; + } +}