#!/bin/bash # 答题红包APP - 腾讯云服务器一键部署脚本 # 作者: QuestionRedPacket Team # 最后更新: 2026-04-09 set -e # 出错时退出 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 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_warning "建议使用root用户运行此脚本" read -p "是否继续? (y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi fi } # 显示欢迎信息 show_welcome() { echo "================================================" echo " 答题红包APP - 腾讯云服务器部署工具" echo "================================================" echo echo "本脚本将帮助您在腾讯云服务器上部署:" echo "1. Node.js 18 + PM2 集群" echo "2. MySQL 8.0 数据库" echo "3. Redis 7.0 缓存" echo "4. Nginx 反向代理 + SSL" echo "5. 必要的防火墙和安全配置" echo echo "请确保:" echo "1. 已购买腾讯云服务器" echo "2. 已配置域名并解析到服务器IP" echo "3. 已在腾讯云控制台申请免费SSL证书" echo read -p "按 Enter 键继续部署,或 Ctrl+C 取消..." echo } # 检查操作系统 check_os() { if [ -f /etc/os-release ]; then . /etc/os-release OS=$NAME VER=$VERSION_ID else OS=$(uname -s) VER=$(uname -r) fi log_info "检测到操作系统: $OS $VER" # 支持的操作系统 if [[ "$OS" == *"Ubuntu"* ]] || [[ "$OS" == *"Debian"* ]]; then OS_TYPE="debian" elif [[ "$OS" == *"CentOS"* ]] || [[ "$OS" == *"Red Hat"* ]] || [[ "$OS" == *"Fedora"* ]]; then OS_TYPE="centos" else log_error "不支持的操作系统: $OS" log_error "仅支持 Ubuntu/Debian/CentOS/RHEL" exit 1 fi } # 更新系统 update_system() { log_info "更新系统包管理器..." if [ "$OS_TYPE" == "debian" ]; then apt update -y apt upgrade -y apt autoremove -y apt clean else yum update -y yum upgrade -y fi log_success "系统更新完成" } # 安装基础工具 install_basic_tools() { log_info "安装基础工具..." if [ "$OS_TYPE" == "debian" ]; then apt install -y curl wget git vim htop net-tools unzip zip else yum install -y curl wget git vim htop net-tools unzip zip fi log_success "基础工具安装完成" } # 安装Node.js 18 install_nodejs() { log_info "安装 Node.js 18..." if command -v node &> /dev/null && node --version | grep -q "v18"; then log_success "Node.js 18 已安装: $(node --version)" return fi if [ "$OS_TYPE" == "debian" ]; then # Ubuntu/Debian curl -fsSL https://deb.nodesource.com/setup_18.x | bash - apt install -y nodejs else # CentOS/RHEL curl -fsSL https://rpm.nodesource.com/setup_18.x | bash - yum install -y nodejs fi log_success "Node.js 安装完成: $(node --version)" log_success "npm 版本: $(npm --version)" } # 安装PM2 install_pm2() { log_info "安装 PM2..." if command -v pm2 &> /dev/null; then log_success "PM2 已安装" return fi npm install -g pm2 pm2 completion install log_success "PM2 安装完成" } # 安装MySQL 8.0 install_mysql() { log_info "安装 MySQL 8.0..." if command -v mysql &> /dev/null; then log_success "MySQL 已安装: $(mysql --version)" return fi if [ "$OS_TYPE" == "debian" ]; then # Ubuntu 20.04+ wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.24-1_all.deb dpkg -i mysql-apt-config_0.8.24-1_all.deb apt update apt install -y mysql-server # 启动服务 systemctl start mysql systemctl enable mysql else # CentOS/RHEL wget https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm rpm -Uvh mysql80-community-release-el7-3.noarch.rpm yum install -y mysql-community-server # 启动服务 systemctl start mysqld systemctl enable mysqld fi log_success "MySQL 安装完成" # 显示初始密码 if [ "$OS_TYPE" == "debian" ]; then log_info "MySQL root 初始密码在: /var/log/mysql/error.log" else log_info "获取MySQL初始密码: grep 'temporary password' /var/log/mysqld.log" fi log_warning "请立即修改MySQL root密码:" echo "ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';" echo "FLUSH PRIVILEGES;" } # 安装Redis install_redis() { log_info "安装 Redis..." if command -v redis-server &> /dev/null; then log_success "Redis 已安装: $(redis-server --version)" return fi if [ "$OS_TYPE" == "debian" ]; then apt install -y redis-server systemctl start redis-server systemctl enable redis-server else yum install -y redis systemctl start redis systemctl enable redis fi log_success "Redis 安装完成" } # 安装Nginx install_nginx() { log_info "安装 Nginx..." if command -v nginx &> /dev/null; then log_success "Nginx 已安装: $(nginx -v 2>&1)" return fi if [ "$OS_TYPE" == "debian" ]; then apt install -y nginx systemctl start nginx systemctl enable nginx else yum install -y nginx systemctl start nginx systemctl enable nginx fi log_success "Nginx 安装完成" } # 配置防火墙 configure_firewall() { log_info "配置防火墙..." if [ "$OS_TYPE" == "debian" ]; then # Ubuntu使用ufw if command -v ufw &> /dev/null; then ufw allow 22/tcp # SSH ufw allow 80/tcp # HTTP ufw allow 443/tcp # HTTPS ufw allow 3000/tcp # API端口(可选) ufw --force enable log_success "UFW防火墙配置完成" else apt install -y ufw ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw allow 3000/tcp ufw --force enable log_success "UFW防火墙安装并配置完成" fi else # CentOS使用firewalld if command -v firewall-cmd &> /dev/null; then firewall-cmd --permanent --add-service=ssh firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --permanent --add-port=3000/tcp firewall-cmd --reload log_success "FirewallD配置完成" else yum install -y firewalld systemctl start firewalld systemctl enable firewalld firewall-cmd --permanent --add-service=ssh firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --permanent --add-port=3000/tcp firewall-cmd --reload log_success "FirewallD安装并配置完成" fi fi } # 部署应用程序 deploy_application() { log_info "开始部署应用程序..." # 创建应用目录 APP_DIR="/var/www/question-redpacket" mkdir -p $APP_DIR # 克隆代码或从本地复制 log_info "检测部署方式..." if [ -f "../api-server/package.json" ]; then log_info "从本地目录复制代码..." cp -r ../api-server/* $APP_DIR/ else log_info "从GitHub克隆代码..." cd $APP_DIR git clone https://github.com/yourusername/question-redpacket.git . cd api-server fi # 安装依赖 cd $APP_DIR/api-server log_info "安装Node.js依赖..." npm ci --only=production # 配置环境变量 if [ ! -f ".env" ]; then log_info "创建环境配置文件..." cp .env.example .env echo log_warning "请编辑环境配置文件: $APP_DIR/api-server/.env" echo "需要配置以下重要参数:" echo "1. DATABASE_URL=mysql://root:你的密码@localhost:3306/question_redpacket" echo "2. JWT_SECRET=生成一个安全的JWT密钥" echo "3. REDIS_HOST=localhost" echo "4. REDIS_PORT=6379" echo read -p "编辑完成后按 Enter 键继续..." fi # 初始化数据库 log_info "初始化数据库..." npx prisma generate npx prisma db push log_success "应用程序部署完成" } # 配置PM2 configure_pm2() { log_info "配置PM2进程管理..." APP_DIR="/var/www/question-redpacket/api-server" cd $APP_DIR # 启动PM2集群 pm2 start ecosystem.config.js --env production pm2 save pm2 startup log_success "PM2配置完成" log_info "PM2状态:" pm2 status } # 配置Nginx configure_nginx() { log_info "配置Nginx反向代理..." # 创建Nginx配置文件 NGINX_CONF="/etc/nginx/sites-available/question-redpacket" if [ "$OS_TYPE" == "debian" ]; then mkdir -p /etc/nginx/sites-available mkdir -p /etc/nginx/sites-enabled fi cat > $NGINX_CONF << 'EOF' # 答题红包APP API服务器配置 server { listen 80; server_name api.yourdomain.com; # 请修改为您的域名 server_name _; # 匹配所有域名,用于测试 # 访问日志 access_log /var/log/nginx/question-redpacket-access.log; error_log /var/log/nginx/question-redpacket-error.log; # Gzip压缩 gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; # 上传文件大小限制 client_max_body_size 50M; # 安全头部 add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # API代理 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_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_cache_bypass $http_upgrade; } # 健康检查端点 location /api/health { access_log off; proxy_pass http://localhost:3000/api/health; proxy_set_header Host $host; } # 静态文件服务(如果需要) location /uploads/ { alias /var/www/question-redpacket/api-server/uploads/; expires 30d; access_log off; } } # SSL配置(需要证书文件) # server { # listen 443 ssl http2; # server_name api.yourdomain.com; # # ssl_certificate /path/to/your/certificate.crt; # ssl_certificate_key /path/to/your/private.key; # # # SSL优化配置 # ssl_protocols TLSv1.2 TLSv1.3; # ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; # ssl_prefer_server_ciphers off; # ssl_session_cache shared:SSL:10m; # ssl_session_timeout 10m; # # # 其余配置与HTTP相同 # # ... 复制上面的location配置 # } EOF log_info "Nginx配置文件已创建: $NGINX_CONF" # 启用站点配置 if [ "$OS_TYPE" == "debian" ]; then ln -sf $NGINX_CONF /etc/nginx/sites-enabled/ else # CentOS通常使用conf.d目录 cp $NGINX_CONF /etc/nginx/conf.d/question-redpacket.conf fi # 测试Nginx配置 nginx -t # 重启Nginx systemctl restart nginx log_success "Nginx配置完成" log_warning "请编辑 $NGINX_CONF 修改server_name为您的域名" log_warning "如需启用SSL,请取消注释SSL配置部分并设置证书路径" } # 创建监控脚本 create_monitoring_scripts() { log_info "创建监控和维护脚本..." SCRIPTS_DIR="/opt/question-redpacket-scripts" mkdir -p $SCRIPTS_DIR # 创建数据库备份脚本 cat > $SCRIPTS_DIR/backup-database.sh << 'EOF' #!/bin/bash # 数据库备份脚本 BACKUP_DIR="/var/backups/mysql" DATE=$(date +%Y%m%d_%H%M%S) DB_NAME="question_redpacket" mkdir -p $BACKUP_DIR # 备份数据库 mysqldump --single-transaction --routines --triggers $DB_NAME > $BACKUP_DIR/${DB_NAME}_${DATE}.sql # 压缩备份 gzip $BACKUP_DIR/${DB_NAME}_${DATE}.sql # 保留最近7天备份 find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete # 记录日志 echo "$(date): 数据库备份完成 - ${DB_NAME}_${DATE}.sql.gz" >> $BACKUP_DIR/backup.log EOF # 创建日志清理脚本 cat > $SCRIPTS_DIR/clean-logs.sh << 'EOF' #!/bin/bash # 日志清理脚本 LOG_DIR="/var/www/question-redpacket/api-server/logs" # 清理30天前的日志 find $LOG_DIR -name "*.log" -mtime +30 -delete # 清理PM2日志 find /root/.pm2/logs -name "*.log" -mtime +30 -delete # 清理Nginx日志(保留7天) find /var/log/nginx -name "*.log" -mtime +7 -exec rm -f {} \; echo "$(date): 日志清理完成" >> /var/log/maintenance.log EOF # 创建系统监控脚本 cat > $SCRIPTS_DIR/system-monitor.sh << 'EOF' #!/bin/bash # 系统监控脚本 DATE=$(date +"%Y-%m-%d %H:%M:%S") LOG_FILE="/var/log/system-monitor.log" echo "=== 系统监控报告 $DATE ===" >> $LOG_FILE echo "CPU使用率: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')%" >> $LOG_FILE echo "内存使用: $(free -m | awk 'NR==2{printf "%.2f%%", $3*100/$2}')" >> $LOG_FILE echo "磁盘使用: $(df -h / | awk 'NR==2{print $5}')" >> $LOG_FILE # 检查服务状态 echo "服务状态:" >> $LOG_FILE systemctl is-active nginx && echo "Nginx: 运行中" >> $LOG_FILE || echo "Nginx: 停止" >> $LOG_FILE systemctl is-active mysql && echo "MySQL: 运行中" >> $LOG_FILE || echo "MySQL: 停止" >> $LOG_FILE systemctl is-active redis && echo "Redis: 运行中" >> $LOG_FILE || echo "Redis: 停止" >> $LOG_FILE # PM2状态 echo "PM2应用状态:" >> $LOG_FILE pm2 status --silent >> $LOG_FILE echo "==========================" >> $LOG_FILE EOF # 设置执行权限 chmod +x $SCRIPTS_DIR/*.sh # 添加到crontab (crontab -l 2>/dev/null; echo "0 2 * * * $SCRIPTS_DIR/backup-database.sh") | crontab - (crontab -l 2>/dev/null; echo "0 4 * * * $SCRIPTS_DIR/clean-logs.sh") | crontab - (crontab -l 2>/dev/null; echo "*/30 * * * * $SCRIPTS_DIR/system-monitor.sh") | crontab - log_success "监控脚本已创建到: $SCRIPTS_DIR" log_info "已设置定时任务:" log_info " 每天 02:00 - 数据库备份" log_info " 每天 04:00 - 日志清理" log_info " 每30分钟 - 系统监控" } # 显示完成信息 show_completion() { echo echo "================================================" echo " 部署完成!" echo "================================================" echo echo "✅ 已成功部署以下服务:" echo " • Node.js + PM2 集群" echo " • MySQL 8.0 数据库" echo " • Redis 7.0 缓存" echo " • Nginx 反向代理" echo " • 防火墙配置" echo echo "📁 应用目录: /var/www/question-redpacket" echo "📝 配置文件: /var/www/question-redpacket/api-server/.env" echo "🔧 管理脚本: /opt/question-redpacket-scripts/" echo echo "🔍 验证部署:" echo " 1. 检查API服务: curl http://localhost:3000/api/health" echo " 2. 检查Nginx: curl http://服务器IP/api/health" echo " 3. 查看PM2状态: pm2 status" echo echo "⚠️ 重要后续步骤:" echo " 1. 编辑环境配置文件 (.env)" echo " 2. 修改MySQL root密码" echo " 3. 配置Nginx域名 (server_name)" echo " 4. 配置SSL证书 (可选但推荐)" echo echo "📞 如有问题,请查看日志文件:" echo " • PM2日志: pm2 logs" echo " • Nginx日志: /var/log/nginx/" echo " • 应用日志: /var/www/question-redpacket/api-server/logs/" echo echo "================================================" } # 主部署流程 main() { check_root show_welcome check_os log_info "开始部署流程..." # 第一阶段:环境准备 update_system install_basic_tools install_nodejs install_pm2 install_mysql install_redis install_nginx configure_firewall # 第二阶段:应用部署 deploy_application configure_pm2 configure_nginx # 第三阶段:运维配置 create_monitoring_scripts show_completion } # 执行主函数 main "$@"