327 lines
9.9 KiB
Bash
Executable File
327 lines
9.9 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# 部署配置
|
||
SERVER_IP="115.190.235.230"
|
||
SSH_PORT="22" # SSH连接端口
|
||
SERVER_USER="root" # 根据实际情况修改用户名
|
||
REMOTE_DIR="/var/www/chinese-family-tree" # 服务器上的部署目录
|
||
APP_PORT="8006" # Next.js 应用端口(对外访问端口)
|
||
|
||
# 数据库配置
|
||
DB_NAME="family_tree"
|
||
DB_USER="family_tree_user"
|
||
DB_PASSWORD="FamilyTree2024" # 简化密码,避免特殊字符问题
|
||
DB_PASSWORD_ENCODED="FamilyTree2024" # URL编码后的密码(如果密码有特殊字符需要编码)
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m' # No Color
|
||
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}中国家谱系统 - 一键部署脚本${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
|
||
# 0. 部署前检查
|
||
echo -e "\n${YELLOW}[0/9] 部署前检查...${NC}"
|
||
|
||
# 检查必要命令
|
||
REQUIRED_COMMANDS=("pnpm" "rsync" "ssh" "nc")
|
||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||
if ! command -v $cmd &> /dev/null; then
|
||
echo -e "${RED}✗ 缺少必要命令: $cmd${NC}"
|
||
echo -e "${YELLOW}请先安装: $cmd${NC}"
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
# 检查本地.env文件
|
||
if [ ! -f .env ]; then
|
||
echo -e "${RED}✗ 本地.env文件不存在${NC}"
|
||
echo -e "${YELLOW}请先创建.env文件配置数据库等信息${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}✓ 部署前检查通过${NC}"
|
||
|
||
# 1. 检查并创建SSH密钥
|
||
echo -e "\n${YELLOW}[1/9] 检查SSH密钥...${NC}"
|
||
if [ ! -f ~/.ssh/id_rsa ]; then
|
||
echo -e "${YELLOW}未找到SSH密钥,正在创建...${NC}"
|
||
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N "" -C "deploy@chinese-family-tree"
|
||
echo -e "${GREEN}✓ SSH密钥创建成功${NC}"
|
||
else
|
||
echo -e "${GREEN}✓ SSH密钥已存在${NC}"
|
||
fi
|
||
|
||
# 2. 测试服务器连接
|
||
echo -e "\n${YELLOW}[2/9] 测试服务器连接...${NC}"
|
||
echo -e "${YELLOW}正在测试 ${SERVER_USER}@${SERVER_IP}:${SSH_PORT}...${NC}"
|
||
|
||
# 测试端口是否开放
|
||
nc -z -w5 $SERVER_IP $SSH_PORT 2>/dev/null
|
||
if [ $? -ne 0 ]; then
|
||
echo -e "${RED}✗ 无法连接到SSH端口 ${SSH_PORT}${NC}"
|
||
echo -e "${YELLOW}请检查:${NC}"
|
||
echo -e " 1. 服务器IP是否正确: ${SERVER_IP}"
|
||
echo -e " 2. SSH端口是否正确: ${SSH_PORT}"
|
||
echo -e " 3. 服务器防火墙是否开放端口 ${SSH_PORT}"
|
||
echo -e " 4. 服务器SSH服务是否运行"
|
||
echo -e "\n${YELLOW}提示:可以尝试手动连接测试:${NC}"
|
||
echo -e " ssh -p ${SSH_PORT} ${SERVER_USER}@${SERVER_IP}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${GREEN}✓ SSH端口 ${SSH_PORT} 可访问${NC}"
|
||
|
||
# 3. 配置免密登录
|
||
echo -e "\n${YELLOW}[3/9] 配置免密登录...${NC}"
|
||
|
||
# 检查是否已经配置免密登录
|
||
ssh -p $SSH_PORT -o BatchMode=yes -o ConnectTimeout=5 $SERVER_USER@$SERVER_IP "echo '已配置免密登录'" 2>/dev/null
|
||
if [ $? -eq 0 ]; then
|
||
echo -e "${GREEN}✓ 免密登录已配置${NC}"
|
||
else
|
||
echo -e "${YELLOW}请输入服务器密码以配置免密登录:${NC}"
|
||
ssh-copy-id -p $SSH_PORT $SERVER_USER@$SERVER_IP
|
||
|
||
if [ $? -eq 0 ]; then
|
||
echo -e "${GREEN}✓ 免密登录配置成功${NC}"
|
||
else
|
||
echo -e "${RED}✗ 免密登录配置失败${NC}"
|
||
echo -e "${YELLOW}请检查:${NC}"
|
||
echo -e " 1. 服务器用户名是否正确: ${SERVER_USER}"
|
||
echo -e " 2. 服务器密码是否正确"
|
||
echo -e " 3. 服务器是否允许密码登录"
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
# 4. 本地构建
|
||
echo -e "\n${YELLOW}[4/9] 本地构建项目...${NC}"
|
||
echo -e "${YELLOW}安装依赖...${NC}"
|
||
pnpm install
|
||
|
||
echo -e "${YELLOW}生成Prisma客户端...${NC}"
|
||
npx prisma generate
|
||
|
||
echo -e "${YELLOW}构建Next.js应用...${NC}"
|
||
pnpm build
|
||
|
||
if [ $? -eq 0 ]; then
|
||
echo -e "${GREEN}✓ 项目构建成功${NC}"
|
||
else
|
||
echo -e "${RED}✗ 项目构建失败${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# 5. 在服务器上创建目录和安装依赖
|
||
echo -e "\n${YELLOW}[5/9] 配置服务器环境...${NC}"
|
||
ssh -p $SSH_PORT $SERVER_USER@$SERVER_IP << 'ENDSSH'
|
||
# 安装Node.js (如果未安装)
|
||
if ! command -v node &> /dev/null; then
|
||
echo "安装Node.js..."
|
||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
||
apt-get install -y nodejs
|
||
fi
|
||
|
||
# 安装pnpm (如果未安装)
|
||
if ! command -v pnpm &> /dev/null; then
|
||
echo "安装pnpm..."
|
||
npm install -g pnpm
|
||
fi
|
||
|
||
# 安装PM2 (如果未安装)
|
||
if ! command -v pm2 &> /dev/null; then
|
||
echo "安装PM2..."
|
||
npm install -g pm2
|
||
fi
|
||
|
||
# 创建部署目录
|
||
mkdir -p /var/www/chinese-family-tree
|
||
ENDSSH
|
||
|
||
echo -e "${GREEN}✓ 服务器环境配置完成${NC}"
|
||
|
||
# 6. 配置数据库
|
||
echo -e "\n${YELLOW}[6/9] 配置PostgreSQL数据库...${NC}"
|
||
ssh -p $SSH_PORT $SERVER_USER@$SERVER_IP bash << ENDSSH
|
||
# 检查PostgreSQL是否安装
|
||
if ! command -v psql &> /dev/null; then
|
||
echo "PostgreSQL未安装,正在安装..."
|
||
apt-get update
|
||
apt-get install -y postgresql postgresql-contrib
|
||
systemctl start postgresql
|
||
systemctl enable postgresql
|
||
fi
|
||
|
||
# 检查数据库是否存在
|
||
DB_EXISTS=\$(sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'")
|
||
|
||
if [ "\$DB_EXISTS" = "1" ]; then
|
||
echo "数据库 $DB_NAME 已存在"
|
||
else
|
||
echo "创建数据库和用户..."
|
||
sudo -u postgres psql << EOF
|
||
CREATE DATABASE $DB_NAME;
|
||
CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD';
|
||
ALTER DATABASE $DB_NAME OWNER TO $DB_USER;
|
||
\\c $DB_NAME
|
||
GRANT ALL ON SCHEMA public TO $DB_USER;
|
||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO $DB_USER;
|
||
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO $DB_USER;
|
||
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO $DB_USER;
|
||
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO $DB_USER;
|
||
EOF
|
||
echo "✓ 数据库创建成功"
|
||
fi
|
||
ENDSSH
|
||
|
||
if [ $? -eq 0 ]; then
|
||
echo -e "${GREEN}✓ 数据库配置完成${NC}"
|
||
else
|
||
echo -e "${RED}✗ 数据库配置失败${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# 7. 上传文件到服务器
|
||
echo -e "\n${YELLOW}[7/9] 上传文件到服务器...${NC}"
|
||
|
||
# 排除不需要上传的文件
|
||
rsync -avz --progress --delete \
|
||
--exclude 'node_modules' \
|
||
--exclude '.git' \
|
||
--exclude '.next/cache' \
|
||
--exclude '.env' \
|
||
--exclude '.env.local' \
|
||
--exclude '*.log' \
|
||
--exclude '*.md' \
|
||
--exclude 'test-*.sh' \
|
||
--exclude 'test-*.js' \
|
||
--exclude 'check-server.sh' \
|
||
--exclude 'deploy-manual.sh' \
|
||
--exclude 'setup-ssh-key.sh' \
|
||
--exclude '*.tar.gz' \
|
||
--exclude 'public/uploads/*' \
|
||
-e "ssh -p $SSH_PORT" \
|
||
./ $SERVER_USER@$SERVER_IP:$REMOTE_DIR/
|
||
|
||
if [ $? -eq 0 ]; then
|
||
echo -e "${GREEN}✓ 文件上传成功${NC}"
|
||
else
|
||
echo -e "${RED}✗ 文件上传失败${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# 8. 配置环境变量
|
||
echo -e "\n${YELLOW}[8/9] 配置环境变量...${NC}"
|
||
ssh -p $SSH_PORT $SERVER_USER@$SERVER_IP bash << ENDSSH
|
||
cd $REMOTE_DIR
|
||
|
||
# 检查.env文件是否存在
|
||
if [ ! -f .env ]; then
|
||
echo "创建.env文件..."
|
||
# 生成随机密钥
|
||
NEXTAUTH_SECRET_VALUE=\$(openssl rand -base64 32)
|
||
|
||
# 创建临时文件
|
||
cat > .env.tmp << 'ENVEOF'
|
||
# 数据库配置
|
||
DATABASE_URL="postgresql://DB_USER_PLACEHOLDER:DB_PASSWORD_PLACEHOLDER@localhost:5432/DB_NAME_PLACEHOLDER"
|
||
|
||
# NextAuth 配置
|
||
NEXTAUTH_URL="http://SERVER_IP_PLACEHOLDER:APP_PORT_PLACEHOLDER"
|
||
NEXTAUTH_SECRET="NEXTAUTH_SECRET_PLACEHOLDER"
|
||
|
||
# 邮箱服务器配置
|
||
SMTP_HOST="smtp.163.com"
|
||
SMTP_PORT="465"
|
||
SMTP_USER="cftservice@163.com"
|
||
SMTP_PASS="SChncqpqS9TDPUD2"
|
||
SMTP_FROM="cftservice@163.com"
|
||
|
||
# 生产环境
|
||
NODE_ENV="production"
|
||
ENVEOF
|
||
|
||
# 替换占位符
|
||
sed "s/DB_USER_PLACEHOLDER/$DB_USER/g" .env.tmp | \\
|
||
sed "s/DB_PASSWORD_PLACEHOLDER/$DB_PASSWORD_ENCODED/g" | \\
|
||
sed "s/DB_NAME_PLACEHOLDER/$DB_NAME/g" | \\
|
||
sed "s/SERVER_IP_PLACEHOLDER/$SERVER_IP/g" | \\
|
||
sed "s/APP_PORT_PLACEHOLDER/$APP_PORT/g" | \\
|
||
sed "s/NEXTAUTH_SECRET_PLACEHOLDER/\$NEXTAUTH_SECRET_VALUE/g" > .env
|
||
|
||
rm .env.tmp
|
||
echo "✓ .env文件创建成功"
|
||
else
|
||
echo "✓ .env文件已存在"
|
||
fi
|
||
ENDSSH
|
||
|
||
if [ $? -eq 0 ]; then
|
||
echo -e "${GREEN}✓ 环境变量配置完成${NC}"
|
||
else
|
||
echo -e "${RED}✗ 环境变量配置失败${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# 9. 在服务器上安装依赖和启动应用
|
||
echo -e "\n${YELLOW}[9/9] 安装依赖并启动应用...${NC}"
|
||
ssh -p $SSH_PORT $SERVER_USER@$SERVER_IP bash << ENDSSH
|
||
cd $REMOTE_DIR
|
||
|
||
# 配置pnpm使用国内镜像(如果还没配置)
|
||
pnpm config get registry | grep -q "npmmirror" || pnpm config set registry https://registry.npmmirror.com
|
||
|
||
# 安装生产依赖(包括prisma)
|
||
echo "安装依赖..."
|
||
pnpm install --prod
|
||
|
||
# 批准prisma构建脚本
|
||
echo "配置Prisma..."
|
||
if ! command -v prisma &> /dev/null; then
|
||
# 如果prisma命令不存在,安装完整依赖
|
||
pnpm install
|
||
fi
|
||
|
||
# 生成Prisma客户端
|
||
echo "生成Prisma客户端..."
|
||
npx prisma generate || pnpm exec prisma generate
|
||
|
||
# 运行数据库迁移
|
||
echo "运行数据库迁移..."
|
||
npx prisma migrate deploy || pnpm exec prisma migrate deploy
|
||
|
||
# 使用PM2启动应用(监听指定端口)
|
||
echo "启动应用..."
|
||
pm2 delete chinese-family-tree 2>/dev/null || true
|
||
PORT=$APP_PORT pm2 start npm --name "chinese-family-tree" -- start
|
||
|
||
# 保存PM2配置
|
||
pm2 save
|
||
|
||
# 配置开机自启(如果还没配置)
|
||
if ! systemctl is-enabled pm2-root &>/dev/null; then
|
||
pm2 startup systemd -u root --hp /root
|
||
fi
|
||
|
||
echo "✓ 应用已启动!"
|
||
ENDSSH
|
||
|
||
if [ $? -eq 0 ]; then
|
||
echo -e "\n${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}✓ 部署成功!${NC}"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
echo -e "${GREEN}应用访问地址: http://${SERVER_IP}:${APP_PORT}${NC}"
|
||
echo -e "${YELLOW}提示:${NC}"
|
||
echo -e " - 查看应用日志: ssh -p ${SSH_PORT} ${SERVER_USER}@${SERVER_IP} 'pm2 logs chinese-family-tree'"
|
||
echo -e " - 重启应用: ssh -p ${SSH_PORT} ${SERVER_USER}@${SERVER_IP} 'pm2 restart chinese-family-tree'"
|
||
echo -e " - 停止应用: ssh -p ${SSH_PORT} ${SERVER_USER}@${SERVER_IP} 'pm2 stop chinese-family-tree'"
|
||
echo -e "${GREEN}========================================${NC}"
|
||
else
|
||
echo -e "${RED}✗ 部署失败${NC}"
|
||
exit 1
|
||
fi
|