#!/bin/bash # ============================================ # FLNXI素材库 - 一键安装脚本 # ============================================ set -e echo "========================================" echo " FLNXI素材库 - 一键安装向导" echo "========================================" echo "" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 检查是否为root用户 if [ "$EUID" -eq 0 ]; then echo -e "${YELLOW}警告: 不建议使用root用户运行此脚本${NC}" read -p "是否继续? (y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi fi # 检查 Docker 是否安装 echo -e "${BLUE}[1/8]${NC} 检查 Docker 环境..." if ! command -v docker &> /dev/null; then echo -e "${RED}错误: 未检测到 Docker,请先安装 Docker${NC}" echo "安装指南: https://docs.docker.com/engine/install/" exit 1 fi if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then echo -e "${RED}错误: 未检测到 Docker Compose,请先安装 Docker Compose${NC}" echo "安装指南: https://docs.docker.com/compose/install/" exit 1 fi # 检查 Docker 权限(自动处理) echo "检查 Docker 权限..." USE_SUDO="" if ! docker ps &> /dev/null; then # 检测到权限问题,自动使用 sudo if command -v sudo &> /dev/null; then echo -e "${YELLOW}检测到 Docker 权限问题,将自动使用 sudo 运行 Docker 命令${NC}" USE_SUDO="sudo" else echo -e "${RED}错误: 无法访问 Docker 且未找到 sudo 命令${NC}" echo "请使用 root 用户运行此脚本,或联系管理员配置 Docker 权限" exit 1 fi fi # 更新 docker 和 docker-compose 命令 if [ -n "$USE_SUDO" ]; then DOCKER_CMD="sudo docker" # 检测 docker-compose 命令 if sudo docker compose version &> /dev/null; then DOCKER_COMPOSE="sudo docker compose" else DOCKER_COMPOSE="sudo docker-compose" fi else DOCKER_CMD="docker" # 检测 docker-compose 命令 if docker compose version &> /dev/null; then DOCKER_COMPOSE="docker compose" else DOCKER_COMPOSE="docker-compose" fi fi # 验证 Docker 是否可用 if ! $DOCKER_CMD ps &> /dev/null; then echo -e "${RED}错误: 无法访问 Docker,请检查权限或使用 root 用户运行${NC}" exit 1 fi echo -e "${GREEN}✓ Docker 环境检查通过${NC}" echo -e "${GREEN}✓ 使用命令: $DOCKER_COMPOSE${NC}" # 创建 .env.production 文件 echo "" echo -e "${BLUE}[2/8]${NC} 配置环境变量..." if [ ! -f .env.production ]; then # 自动检测服务器IP echo "正在自动检测服务器IP地址..." # 尝试多种方法获取IP SERVER_IP="" # 方法1: 通过 ip route 获取 if command -v ip &> /dev/null; then SERVER_IP=$(ip route get 1 2>/dev/null | awk '{print $7; exit}') fi # 方法2: 通过 hostname 获取 if [ -z "$SERVER_IP" ] && command -v hostname &> /dev/null; then SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}') fi # 方法3: 通过 ifconfig 获取 if [ -z "$SERVER_IP" ] && command -v ifconfig &> /dev/null; then SERVER_IP=$(ifconfig 2>/dev/null | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | head -n 1) fi # 如果自动检测失败,提示用户输入 if [ -z "$SERVER_IP" ]; then echo -e "${YELLOW}无法自动检测IP地址${NC}" read -p "请输入服务器IP地址: " SERVER_IP else echo -e "${GREEN}检测到服务器IP: $SERVER_IP${NC}" read -p "是否使用此IP? (Y/n): " -n 1 -r echo if [[ $REPLY =~ ^[Nn]$ ]]; then read -p "请输入服务器IP地址: " SERVER_IP fi fi # 询问端口配置 echo "" echo "端口配置 (直接回车使用默认值):" read -p "应用端口 [4320]: " APP_PORT APP_PORT=${APP_PORT:-4320} read -p "MinIO API端口 [9000]: " MINIO_API_PORT MINIO_API_PORT=${MINIO_API_PORT:-9000} read -p "MinIO控制台端口 [9001]: " MINIO_CONSOLE_PORT MINIO_CONSOLE_PORT=${MINIO_CONSOLE_PORT:-9001} # 生成随机密码 echo "" echo "生成安全密码..." POSTGRES_PASSWORD=$(openssl rand -base64 16 2>/dev/null || cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) MINIO_ROOT_PASSWORD=$(openssl rand -base64 16 2>/dev/null || cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) NEXTAUTH_SECRET=$(openssl rand -base64 32 2>/dev/null || cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) # 询问初始管理员账号 echo "" echo "配置初始管理员账号 (首次登录使用):" read -p "管理员邮箱 [admin@flnxi.com]: " INIT_ADMIN_EMAIL INIT_ADMIN_EMAIL=${INIT_ADMIN_EMAIL:-admin@flnxi.com} read -sp "管理员密码 (输入时不会显示): " INIT_ADMIN_PASSWORD echo if [ -z "$INIT_ADMIN_PASSWORD" ]; then INIT_ADMIN_PASSWORD=$(openssl rand -base64 16 2>/dev/null || cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) echo -e "${YELLOW}已自动生成密码,请查看下方保存的信息${NC}" fi # 选择部署环境 echo "" echo "选择部署环境:" echo " 1) 测试环境 (test) - 使用测试镜像标签(需要登录)" echo " 2) 正式环境 (prod) - 使用正式镜像标签(公开,无需登录)" read -p "请选择 [1/2,默认: 2]: " ENV_CHOICE ENV_CHOICE=${ENV_CHOICE:-2} if [ "$ENV_CHOICE" = "1" ]; then IMAGE_ENV="test" IMAGE_TAG="test" HARBOR_PROJECT="flnxi" # 使用同一个项目 echo -e "${YELLOW}已选择: 测试环境(需要 Harbor 登录)${NC}" # 测试环境需要登录 Harbor(因为测试标签可能是私有的) echo "" echo "Harbor 镜像仓库配置(测试环境需要登录):" read -p "Harbor 地址 [harbor.flnxi.com]: " HARBOR_URL HARBOR_URL=${HARBOR_URL:-harbor.flnxi.com} read -p "Harbor 用户名: " HARBOR_USERNAME read -sp "Harbor 密码: " HARBOR_PASSWORD echo else IMAGE_ENV="prod" IMAGE_TAG="latest" HARBOR_PROJECT="flnxi" # 使用同一个项目 echo -e "${GREEN}已选择: 正式环境(公开镜像,无需登录)${NC}" # 正式环境使用公开镜像,无需登录 HARBOR_URL="harbor.flnxi.com" HARBOR_USERNAME="" HARBOR_PASSWORD="" fi # 创建 .env.production 文件(客户安装使用) cat > .env.production << EOF # FLNXI素材库 - 生产环境配置 # 生成时间: $(date) # 服务器配置 SERVER_IP=$SERVER_IP APP_PORT=$APP_PORT # 数据库配置 POSTGRES_USER=postgres POSTGRES_PASSWORD=$POSTGRES_PASSWORD POSTGRES_DB=flnxi # MinIO 配置 MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD MINIO_API_PORT=$MINIO_API_PORT MINIO_CONSOLE_PORT=$MINIO_CONSOLE_PORT S3_BUCKET=flnxi-materials # 应用安全配置 NEXTAUTH_SECRET=$NEXTAUTH_SECRET NEXTAUTH_URL=http://$SERVER_IP:$APP_PORT APP_PUBLIC_URL=http://$SERVER_IP:$APP_PORT # 初始管理员账号 INIT_ADMIN_EMAIL=$INIT_ADMIN_EMAIL INIT_ADMIN_PASSWORD=$INIT_ADMIN_PASSWORD # 镜像环境配置 IMAGE_ENV=$IMAGE_ENV IMAGE_TAG=$IMAGE_TAG HARBOR_PROJECT=$HARBOR_PROJECT DOCKER_REGISTRY=harbor.flnxi.com/$HARBOR_PROJECT # Harbor 配置(如果配置了) EOF if [ -n "$HARBOR_USERNAME" ] && [ -n "$HARBOR_PASSWORD" ]; then cat >> .env.production << EOF HARBOR_URL=$HARBOR_URL HARBOR_USERNAME=$HARBOR_USERNAME HARBOR_PASSWORD=$HARBOR_PASSWORD EOF fi echo -e "${GREEN}✓ 环境配置文件已创建${NC}" echo "" echo -e "${YELLOW}重要信息 (请保存):${NC}" echo "----------------------------------------" echo "服务器IP: $SERVER_IP" echo "应用端口: $APP_PORT" echo "应用地址: http://$SERVER_IP:$APP_PORT" echo "" echo "初始管理员账号:" echo " - 邮箱: $INIT_ADMIN_EMAIL" echo " - 密码: $INIT_ADMIN_PASSWORD" echo "" echo "MinIO控制台: http://$SERVER_IP:$MINIO_CONSOLE_PORT" echo " - 用户名: minioadmin" echo " - 密码: $MINIO_ROOT_PASSWORD" echo "" echo "数据库信息:" echo " - 数据库名: flnxi" echo " - 用户名: postgres" echo " - 密码: $POSTGRES_PASSWORD" echo "----------------------------------------" echo "" read -p "按回车键继续安装..." else echo -e "${GREEN}✓ 检测到已存在的配置文件${NC}" if [ -f .env.production ]; then source .env.production elif [ -f .env ]; then source .env fi fi # 创建必要的目录 echo "" echo -e "${BLUE}[3/8]${NC} 创建数据目录..." mkdir -p uploads chmod 755 uploads echo -e "${GREEN}✓ 数据目录创建完成${NC}" # 登录 Harbor(如果配置了) if [ -n "$HARBOR_USERNAME" ] && [ -n "$HARBOR_PASSWORD" ]; then echo "" echo -e "${BLUE}[4/8]${NC} 登录 Harbor 镜像仓库..." echo "$HARBOR_PASSWORD" | docker login $HARBOR_URL -u $HARBOR_USERNAME --password-stdin if [ $? -eq 0 ]; then echo -e "${GREEN}✓ Harbor 登录成功${NC}" else echo -e "${YELLOW}警告: Harbor 登录失败,将尝试继续...${NC}" fi else echo "" echo -e "${BLUE}[4/8]${NC} 跳过 Harbor 登录(使用公开镜像或已登录)..." fi # 停止旧容器(如果存在) echo "" echo -e "${BLUE}[5/8]${NC} 清理旧容器..." $DOCKER_COMPOSE -f docker-compose.prod.yml down 2>/dev/null || true echo -e "${GREEN}✓ 清理完成${NC}" # 拉取镜像(从 Harbor) echo "" echo -e "${BLUE}[6/8]${NC} 拉取 Docker 镜像..." echo "这可能需要几分钟时间,请耐心等待..." $DOCKER_COMPOSE -f docker-compose.prod.yml pull echo -e "${GREEN}✓ 镜像拉取完成${NC}" # 启动服务 echo "" echo -e "${BLUE}[7/8]${NC} 启动服务..." $DOCKER_COMPOSE -f docker-compose.prod.yml up -d echo -e "${GREEN}✓ 服务启动成功${NC}" # 等待服务就绪 echo "" echo -e "${BLUE}[8/8]${NC} 等待服务启动..." echo "正在等待数据库启动..." sleep 10 # 检查服务状态 echo "" echo "检查服务状态..." $DOCKER_COMPOSE -f docker-compose.prod.yml ps # 初始化数据库 echo "" echo "初始化数据库..." max_retries=30 retry_count=0 while [ $retry_count -lt $max_retries ]; do if $DOCKER_COMPOSE -f docker-compose.prod.yml exec -T app npx prisma db push --accept-data-loss 2>/dev/null; then echo -e "${GREEN}✓ 数据库初始化成功${NC}" break else retry_count=$((retry_count + 1)) if [ $retry_count -lt $max_retries ]; then echo "等待应用启动... ($retry_count/$max_retries)" sleep 5 else echo -e "${RED}数据库初始化失败,请稍后手动执行:${NC}" echo " $DOCKER_COMPOSE -f docker-compose.prod.yml exec app npx prisma db push" fi fi done # 显示安装完成信息 echo "" echo "========================================" echo -e "${GREEN} 安装完成!${NC}" echo "========================================" echo "" echo -e "${BLUE}访问地址:${NC}" echo " 应用首页: http://$SERVER_IP:$APP_PORT" echo " MinIO控制台: http://$SERVER_IP:$MINIO_CONSOLE_PORT" echo "" echo -e "${BLUE}MinIO 管理员账号:${NC}" echo " 用户名: minioadmin" echo " 密码: $MINIO_ROOT_PASSWORD" echo "" echo -e "${BLUE}首次使用:${NC}" echo " 1. 访问 http://$SERVER_IP:$APP_PORT" echo " 2. 使用初始管理员账号登录:" echo " - 邮箱: $INIT_ADMIN_EMAIL" echo " - 密码: $INIT_ADMIN_PASSWORD" echo " 3. 登录后可在系统设置中修改密码" echo "" echo -e "${BLUE}常用命令:${NC}" echo " 查看日志: $DOCKER_COMPOSE -f docker-compose.prod.yml logs -f" echo " 重启服务: $DOCKER_COMPOSE -f docker-compose.prod.yml restart" echo " 停止服务: $DOCKER_COMPOSE -f docker-compose.prod.yml down" echo " 启动服务: $DOCKER_COMPOSE -f docker-compose.prod.yml up -d" echo "" echo -e "${YELLOW}注意事项:${NC}" echo " - 所有配置信息已保存在 .env.production 文件中" echo " - 请妥善保管初始管理员账号、数据库密码和MinIO密码" echo " - 数据存储在 Docker volumes 中,卸载前请备份" echo "" echo "========================================"