#!/bin/bash # Author: emotion-museum team # Created: 2026-05-12 # Purpose: 统一部署脚本 - 合并 deploy-all.sh / deploy-to-prod.sh / deploy-domain.sh # # 使用方法: # bash deploy.sh # 部署所有服务 # bash deploy.sh backend # 仅部署后端 # bash deploy.sh frontend # 仅部署前端 # bash deploy.sh admin # 仅部署管理后台 # bash deploy.sh life-script # 仅部署 Life-Script # bash deploy.sh ssl # 仅申请 SSL 证书 # bash deploy.sh nginx # 仅部署 Nginx 配置 # bash deploy.sh verify # 仅验证部署结果 # bash deploy.sh all # 部署所有服务(同无参数) set -e # ============================================================================ # 配置 # ============================================================================ SERVER_IP="101.200.208.45" USERNAME="root" DOMAIN="lifescript.happylifeos.com" # ============================================================================ # 日志 # ============================================================================ RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_section() { echo -e "\n${BLUE}╔═══════════════════════════════════════════════════════════╗${NC}"; echo -e "${BLUE}║${NC} $1"; echo -e "${BLUE}╚═══════════════════════════════════════════════════════════╝${NC}\n"; } # ============================================================================ # 工具函数 # ============================================================================ check_ssh() { log_info "检查 SSH 连接..." if ssh -o BatchMode=yes -o ConnectTimeout=10 ${USERNAME}@${SERVER_IP} "echo ok" > /dev/null 2>&1; then log_info "SSH 连接正常" else log_error "SSH 连接失败,请先配置免密登录: ssh ${USERNAME}@${SERVER_IP}" exit 1 fi } # ============================================================================ # Nginx 配置 # ============================================================================ deploy_nginx() { log_section "部署 Nginx 配置" if [ ! -f "conf/emotion-museum.conf" ]; then log_error "Nginx 配置文件不存在: conf/emotion-museum.conf" return 1 fi log_info "上传 Nginx 配置文件..." scp conf/emotion-museum.conf ${USERNAME}@${SERVER_IP}:/etc/nginx/sites-available/${DOMAIN}.conf log_info "启用站点配置..." ssh ${USERNAME}@${SERVER_IP} "ln -snf /etc/nginx/sites-available/${DOMAIN}.conf /etc/nginx/sites-enabled/${DOMAIN}.conf && rm -f /etc/nginx/sites-enabled/default" log_info "验证 Nginx 配置..." if ssh ${USERNAME}@${SERVER_IP} "nginx -t"; then ssh ${USERNAME}@${SERVER_IP} "systemctl reload nginx" log_info "✅ Nginx 配置重载完成" else log_error "❌ Nginx 配置验证失败" return 1 fi } # ============================================================================ # 后端 - 调用 backend-single/deploy.sh # ============================================================================ deploy_backend() { log_section "部署后端服务" if [ ! -f "backend-single/deploy.sh" ]; then log_error "后端部署脚本不存在: backend-single/deploy.sh" return 1 fi log_info "执行后端部署..." cd backend-single if bash deploy.sh remote; then cd .. log_info "✅ 后端部署完成" return 0 else cd .. log_error "❌ 后端部署失败" return 1 fi } # ============================================================================ # 前端 - 调用 web/deploy.sh # ============================================================================ deploy_frontend() { log_section "部署用户前端" if [ ! -f "web/deploy.sh" ]; then log_error "前端部署脚本不存在: web/deploy.sh" return 1 fi log_info "执行前端部署..." cd web if bash deploy.sh; then cd .. log_info "✅ 前端部署完成" return 0 else cd .. log_error "❌ 前端部署失败" return 1 fi } # ============================================================================ # 管理后台 - 调用 web-admin/deploy.py # ============================================================================ deploy_admin() { log_section "部署管理后台" if [ ! -f "web-admin/deploy.sh" ]; then log_error "管理后台部署脚本不存在: web-admin/deploy.sh" return 1 fi log_info "执行管理后台部署..." cd web-admin if bash deploy.sh; then cd .. log_info "✅ 管理后台部署完成" return 0 else cd .. log_error "❌ 管理后台部署失败" return 1 fi } # ============================================================================ # Life-Script - 调用 life-script/deploy.sh # ============================================================================ deploy_life_script() { log_section "部署 Life-Script" if [ ! -f "life-script/deploy.sh" ]; then log_error "Life-Script 部署脚本不存在: life-script/deploy.sh" return 1 fi log_info "执行 Life-Script 部署..." cd life-script if bash deploy.sh; then cd .. log_info "✅ Life-Script 部署完成" return 0 else cd .. log_error "❌ Life-Script 部署失败" return 1 fi } # ============================================================================ # 验证部署 # ============================================================================ verify_deploy() { log_section "验证部署" log_info "检查 HTTPS 访问..." curl -k -s -o /dev/null -w " 前端页面: HTTP %{http_code}\n" https://${DOMAIN}/ || log_warn "前端访问异常" curl -k -s -o /dev/null -w " 管理后台: HTTP %{http_code}\n" https://${DOMAIN}/emotion-museum-admin/ || log_warn "管理后台访问异常" curl -k -s -o /dev/null -w " API 代理: HTTP %{http_code}\n" https://${DOMAIN}/api/ || log_warn "API 访问异常" curl -k -s -o /dev/null -w " HTTP 跳转: HTTP %{http_code}\n" http://${DOMAIN}/ || log_warn "HTTP 跳转异常" log_info "✅ 验证完成" } # ============================================================================ # 主程序 # ============================================================================ main() { DEPLOY_TYPE="${1:-all}" START_TIME=$(date +%s) log_section "情绪博物馆 - 统一部署" log_info "部署类型: ${DEPLOY_TYPE}" log_info "部署时间: $(date '+%Y-%m-%d %H:%M:%S')" case "$DEPLOY_TYPE" in backend) check_ssh deploy_backend ;; frontend) check_ssh deploy_frontend ;; admin) check_ssh deploy_admin ;; life-script) check_ssh deploy_life_script ;; nginx) check_ssh deploy_nginx ;; verify) verify_deploy ;; all) check_ssh deploy_nginx || true deploy_backend deploy_frontend deploy_admin deploy_life_script verify_deploy ;; *) log_error "无效的部署类型: $DEPLOY_TYPE" echo "使用方法: bash deploy.sh [backend|frontend|admin|life-script|nginx|verify|all]" exit 1 ;; esac END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) log_section "部署完成 (耗时 ${DURATION}s)" log_info "用户前端: https://${DOMAIN}/" log_info "管理后台: https://${DOMAIN}/emotion-museum-admin/" log_info "Life-Script: https://${DOMAIN}/life-script/" log_info "API 地址: https://${DOMAIN}/api" log_info "WebSocket: wss://${DOMAIN}/ws" } main "$@"