#!/bin/bash # 服务器迁移脚本 # 从旧服务器迁移到新服务器(包括数据库数据) set -e # 遇到错误立即退出 # 配置 OLD_SERVER="156.225.27.52" OLD_PORT="5204" OLD_USER="root" OLD_PASS="${DEPLOY_SSH_PASSWORD:?set DEPLOY_SSH_PASSWORD}" NEW_SERVER="114.66.31.51" NEW_PORT="22" NEW_USER="root" NEW_PASS="vsvhSIHN5531" PROJECT_DIR="/var/www/ai-chatbot" BACKUP_DIR="/tmp/ai-chatbot-migration" TIMESTAMP=$(date +%Y%m%d_%H%M%S) echo "==========================================" echo "AI Chatbot 服务器迁移脚本" echo "==========================================" echo "旧服务器: $OLD_USER@$OLD_SERVER:$OLD_PORT" echo "新服务器: $NEW_USER@$NEW_SERVER:$NEW_PORT" echo "时间: $(date)" echo "==========================================" echo "" # 检查 sshpass 是否安装 if ! command -v sshpass &> /dev/null; then echo "❌ sshpass 未安装,正在安装..." if [[ "$OSTYPE" == "darwin"* ]]; then brew install hudochenkov/sshpass/sshpass || echo "请手动安装: brew install hudochenkov/sshpass/sshpass" else sudo apt-get update && sudo apt-get install -y sshpass fi fi # 测试连接 echo "🔍 测试服务器连接..." echo "测试旧服务器连接..." if sshpass -p "$OLD_PASS" ssh -p "$OLD_PORT" -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$OLD_USER@$OLD_SERVER" "echo '连接成功'" > /dev/null 2>&1; then echo "✅ 旧服务器连接正常" else echo "❌ 无法连接到旧服务器" exit 1 fi echo "测试新服务器连接..." if sshpass -p "$NEW_PASS" ssh -p "$NEW_PORT" -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$NEW_USER@$NEW_SERVER" "echo '连接成功'" > /dev/null 2>&1; then echo "✅ 新服务器连接正常" else echo "❌ 无法连接到新服务器" exit 1 fi # 步骤1: 在旧服务器上备份数据库 echo "" echo "📦 步骤 1/9: 在旧服务器上备份数据库..." sshpass -p "$OLD_PASS" ssh -p "$OLD_PORT" "$OLD_USER@$OLD_SERVER" << 'EOF' cd /var/www/ai-chatbot if [ ! -f .env.local ]; then echo "❌ 未找到 .env.local 文件" exit 1 fi # 读取 POSTGRES_URL POSTGRES_URL=$(grep "^POSTGRES_URL=" .env.local | cut -d '=' -f2- | tr -d '"' | tr -d "'") if [ -z "$POSTGRES_URL" ]; then echo "❌ 无法读取 POSTGRES_URL" exit 1 fi # 解析数据库连接信息 DB_NAME=$(echo "$POSTGRES_URL" | sed -n 's|.*/\([^?]*\)$|\1|p') DB_USER=$(echo "$POSTGRES_URL" | sed -n 's|.*://\([^:]*\):.*|\1|p') DB_PASS=$(echo "$POSTGRES_URL" | sed -n 's|.*://[^:]*:\([^@]*\)@.*|\1|p') DB_HOST=$(echo "$POSTGRES_URL" | sed -n 's|.*@\([^:]*\):.*|\1|p') DB_PORT=$(echo "$POSTGRES_URL" | sed -n 's|.*:\([0-9]*\)/.*|\1|p') # 如果端口为空,使用默认端口 if [ -z "$DB_PORT" ]; then DB_PORT=5432 fi echo "数据库信息: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME" # 创建备份目录 mkdir -p /tmp/ai-chatbot-backup # 使用 pg_dump 备份数据库 export PGPASSWORD="$DB_PASS" BACKUP_FILE="/tmp/ai-chatbot-backup/database_backup_$(date +%Y%m%d_%H%M%S).dump" pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -F c -f "$BACKUP_FILE" 2>&1 if [ $? -eq 0 ]; then echo "✅ 数据库备份完成: $BACKUP_FILE" ls -lh "$BACKUP_FILE" else echo "❌ 数据库备份失败" exit 1 fi EOF # 步骤2: 下载备份文件 echo "" echo "📥 步骤 2/9: 下载数据库备份文件..." mkdir -p "$BACKUP_DIR" LATEST_BACKUP=$(sshpass -p "$OLD_PASS" ssh -p "$OLD_PORT" "$OLD_USER@$OLD_SERVER" "ls -t /tmp/ai-chatbot-backup/*.dump 2>/dev/null | head -1") if [ -z "$LATEST_BACKUP" ]; then echo "❌ 未找到备份文件" exit 1 fi echo "正在下载: $LATEST_BACKUP" sshpass -p "$OLD_PASS" scp -P "$OLD_PORT" "$OLD_USER@$OLD_SERVER:$LATEST_BACKUP" "$BACKUP_DIR/database.dump" if [ $? -eq 0 ]; then echo "✅ 数据库备份文件已下载 ($(du -h "$BACKUP_DIR/database.dump" | cut -f1))" else echo "❌ 数据库备份文件下载失败" exit 1 fi # 步骤3: 下载项目文件和配置 echo "" echo "📥 步骤 3/9: 下载项目文件..." sshpass -p "$OLD_PASS" ssh -p "$OLD_PORT" "$OLD_USER@$OLD_SERVER" << 'EOF' cd /var/www/ai-chatbot # 创建项目打包(排除 node_modules 和 .next) tar --exclude='node_modules' \ --exclude='.next' \ --exclude='.git' \ --exclude='*.log' \ -czf /tmp/ai-chatbot-backup/project.tar.gz . echo "✅ 项目文件打包完成" EOF sshpass -p "$OLD_PASS" scp -P "$OLD_PORT" "$OLD_USER@$OLD_SERVER:/tmp/ai-chatbot-backup/project.tar.gz" "$BACKUP_DIR/" echo "✅ 项目文件已下载" # 下载环境变量文件 echo "" echo "📥 步骤 4/9: 下载环境变量文件..." sshpass -p "$OLD_PASS" scp -P "$OLD_PORT" "$OLD_USER@$OLD_SERVER:/var/www/ai-chatbot/.env.local" "$BACKUP_DIR/.env.local" 2>/dev/null || echo "⚠️ 未找到 .env.local 文件(将在新服务器上手动配置)" echo "✅ 环境变量文件已下载" # 步骤5: 在新服务器上初始化环境 echo "" echo "🔧 步骤 5/9: 在新服务器上初始化环境..." sshpass -p "$NEW_PASS" ssh -p "$NEW_PORT" "$NEW_USER@$NEW_SERVER" << 'ENVEOF' # 更新系统 apt-get update -qq # 安装必要的工具 DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ curl \ wget \ git \ build-essential \ postgresql-client \ postgresql \ nginx \ certbot \ python3-certbot-nginx # 安装 Node.js 20.x if ! command -v node &> /dev/null; then curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y -qq nodejs fi # 安装 PM2 if ! command -v pm2 &> /dev/null; then npm install -g pm2 fi # 安装 pnpm if ! command -v pnpm &> /dev/null; then npm install -g pnpm fi echo "✅ 环境初始化完成" ENVEOF # 步骤6: 创建数据库 echo "" echo "🗄️ 步骤 6/9: 在新服务器上创建数据库..." sshpass -p "$NEW_PASS" ssh -p "$NEW_PORT" "$NEW_USER@$NEW_SERVER" << 'DBEOF' # 启动 PostgreSQL systemctl start postgresql systemctl enable postgresql # 读取旧的环境变量(如果存在)来获取数据库信息 # 这里我们创建新的数据库,稍后会导入数据 sudo -u postgres psql << 'PSQLEOF' -- 创建数据库(如果不存在) SELECT 'CREATE DATABASE ai_chatbot' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'ai_chatbot')\gexec -- 创建用户(如果不存在) DO \$\$ BEGIN IF NOT EXISTS (SELECT FROM pg_user WHERE usename = 'chatbot_user') THEN CREATE USER chatbot_user WITH PASSWORD 'chatbot_password_change_me'; END IF; END \$\$; -- 授权 GRANT ALL PRIVILEGES ON DATABASE ai_chatbot TO chatbot_user; ALTER DATABASE ai_chatbot OWNER TO chatbot_user; PSQLEOF echo "✅ 数据库创建完成" DBEOF # 步骤7: 上传文件到新服务器 echo "" echo "📤 步骤 7/9: 上传文件到新服务器..." sshpass -p "$NEW_PASS" ssh -p "$NEW_PORT" "$NEW_USER@$NEW_SERVER" "mkdir -p $PROJECT_DIR" sshpass -p "$NEW_PASS" scp -P "$NEW_PORT" "$BACKUP_DIR/project.tar.gz" "$NEW_USER@$NEW_SERVER:/tmp/" sshpass -p "$NEW_PASS" scp -P "$NEW_PORT" "$BACKUP_DIR/database.dump" "$NEW_USER@$NEW_SERVER:/tmp/" # 在新服务器上解压项目 sshpass -p "$NEW_PASS" ssh -p "$NEW_PORT" "$NEW_USER@$NEW_SERVER" << 'EXTRACTEOF' cd /var/www/ai-chatbot tar -xzf /tmp/project.tar.gz chown -R root:root . echo "✅ 项目文件已解压" EXTRACTEOF # 步骤8: 在新服务器上配置和恢复 echo "" echo "⚙️ 步骤 8/9: 在新服务器上配置和恢复..." sshpass -p "$NEW_PASS" ssh -p "$NEW_PORT" "$NEW_USER@$NEW_SERVER" << 'CONFIGEOF' cd /var/www/ai-chatbot # 如果存在旧的环境变量文件,需要更新数据库连接信息 if [ -f .env.local ]; then # 更新 POSTGRES_URL 为新服务器的数据库 sed -i 's|POSTGRES_URL=.*|POSTGRES_URL=postgresql://chatbot_user:chatbot_password_change_me@localhost:5432/ai_chatbot|g' .env.local # 更新 AUTH_URL 为新服务器地址 sed -i "s|AUTH_URL=.*|AUTH_URL=http://114.66.31.51|g" .env.local else # 创建新的环境变量文件 cat > .env.local << 'ENVFILE' POSTGRES_URL=postgresql://chatbot_user:chatbot_password_change_me@localhost:5432/ai_chatbot AUTH_SECRET=$(openssl rand -base64 32) AUTH_URL=http://114.66.31.51 NODE_ENV=production ENVFILE fi # 导入数据库 echo "正在导入数据库..." export PGPASSWORD="chatbot_password_change_me" # 尝试恢复,忽略已存在的错误 pg_restore -h localhost -p 5432 -U chatbot_user -d ai_chatbot -c --no-owner --no-privileges /tmp/database.dump 2>&1 | grep -v -E "(already exists|does not exist|ERROR.*already)" || true echo "✅ 数据库导入完成(已忽略重复项)" # 安装依赖 echo "正在安装依赖..." pnpm install --frozen-lockfile echo "✅ 依赖安装完成" # 运行数据库迁移(如果需要) echo "正在运行数据库迁移..." pnpm db:migrate || echo "⚠️ 数据库迁移跳过或失败" echo "✅ 数据库迁移完成" # 构建项目 echo "正在构建项目..." pnpm build echo "✅ 项目构建完成" # 配置 PM2 echo "正在配置 PM2..." cat > ecosystem.config.js << 'PM2EOF' module.exports = { apps: [{ name: 'ai-chatbot', script: 'node_modules/next/dist/bin/next', args: 'start', cwd: '/var/www/ai-chatbot', instances: 1, exec_mode: 'fork', env: { NODE_ENV: 'production', PORT: 3000 }, error_file: '/var/log/pm2/ai-chatbot-error.log', out_file: '/var/log/pm2/ai-chatbot-out.log', log_date_format: 'YYYY-MM-DD HH:mm:ss Z', merge_logs: true, autorestart: true, max_memory_restart: '1G' }] }; PM2EOF # 启动应用 pm2 delete ai-chatbot 2>/dev/null || true pm2 start ecosystem.config.js pm2 save pm2 startup systemd -u root --hp /root || true echo "✅ PM2 配置完成" # 配置 Nginx echo "正在配置 Nginx..." cat > /etc/nginx/sites-available/ai-chatbot << 'NGINXEOF' server { listen 80; server_name 114.66.31.51; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; 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; proxy_cache_bypass $http_upgrade; proxy_read_timeout 300s; proxy_connect_timeout 75s; } } NGINXEOF ln -sf /etc/nginx/sites-available/ai-chatbot /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default nginx -t && systemctl reload nginx echo "✅ Nginx 配置完成" # 清理临时文件 rm -f /tmp/project.tar.gz /tmp/database.dump echo "✅ 临时文件已清理" echo "" echo "==========================================" echo "✅ 迁移完成!" echo "==========================================" echo "新服务器地址: http://114.66.31.51" echo "请检查以下内容:" echo "1. 检查 .env.local 文件中的配置(特别是数据库密码)" echo "2. 检查 PM2 状态: pm2 status" echo "3. 检查日志: pm2 logs ai-chatbot" echo "4. 访问网站验证功能" echo "==========================================" CONFIGEOF echo "" echo "✅ 步骤 9/9: 清理临时文件..." rm -rf "$BACKUP_DIR" echo "✅ 临时文件已清理" echo "" echo "🎉 迁移脚本执行完成!" echo "" echo "📝 后续步骤:" echo "1. 连接到新服务器: ssh -p $NEW_PORT $NEW_USER@$NEW_SERVER" echo "2. 检查数据库密码: cd $PROJECT_DIR && cat .env.local" echo "3. 如果需要,更新数据库密码并更新 .env.local" echo "4. 检查服务状态: pm2 status && pm2 logs" echo "5. 访问网站: http://$NEW_SERVER" echo "" echo "⚠️ 重要提示:" echo "- 请更新数据库密码(.env.local 中的 POSTGRES_URL)" echo "- 如果使用域名,请更新 AUTH_URL" echo "- 检查所有环境变量是否正确配置"