This commit is contained in:
freedakgmail
2025-11-23 19:38:51 +08:00
parent e44dd0bd95
commit 3b0d8255f6
649 changed files with 656698 additions and 4133 deletions
Executable
+325
View File
@@ -0,0 +1,325 @@
#!/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 \
--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' \
-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