Files
chinese-family-tree-2/deploy.sh
T
2025-11-28 11:50:24 +08:00

328 lines
9.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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"
NEXTAUTH_TRUST_HOST="true"
# 邮箱服务器配置
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