Files
selfrelease 639344dc45 0.9.0.1
2025-12-22 16:49:58 +08:00

342 lines
10 KiB
Bash
Executable File
Raw Permalink 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="180.76.240.104"
SSH_PORT="22" # SSH连接端口
SERVER_USER="root" # 根据实际情况修改用户名
REMOTE_DIR="/var/www/chinese-family-tree" # 服务器上的部署目录
APP_PORT="8006" # Next.js 应用端口(对外访问端口)
SSH_HOST="baidu-server"
# 数据库配置
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}"
echo -e "${GREEN}✓ 使用已配置的SSH免密登录(~/.ssh/config: ${SSH_HOST}${NC}"
# 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 -o BatchMode=yes -o ConnectTimeout=5 $SSH_HOST "echo '已配置免密登录'" 2>/dev/null
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 免密登录已配置${NC}"
else
echo -e "${RED}✗ 免密登录未配置或无法使用${NC}"
echo -e "${YELLOW}请先在本机配置好免密登录后再重试:${NC}"
echo -e " ssh ${SSH_HOST}"
exit 1
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 $SSH_HOST << '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 $SSH_HOST 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 USAGE, CREATE 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 PRIVILEGES ON TABLES TO $DB_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES 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" \
./ $SSH_HOST:$REMOTE_DIR/
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 文件上传成功${NC}"
else
echo -e "${RED}✗ 文件上传失败${NC}"
exit 1
fi
# 同步上传文件目录(如果存在)
if [ -d "public/uploads" ] && [ "$(ls -A public/uploads 2>/dev/null)" ]; then
echo -e "${YELLOW}同步上传文件目录...${NC}"
rsync -avz --progress \
-e "ssh" \
./public/uploads/ $SSH_HOST:$REMOTE_DIR/public/uploads/
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ 上传文件同步成功${NC}"
else
echo -e "${YELLOW}⚠ 上传文件同步失败(非致命错误)${NC}"
fi
else
echo -e "${YELLOW}⚠ 本地无上传文件需要同步${NC}"
fi
# 8. 配置环境变量
echo -e "\n${YELLOW}[8/9] 配置环境变量...${NC}"
ssh $SSH_HOST 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 $SSH_HOST 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
# 确保数据库用户有正确的权限
echo "检查数据库权限..."
sudo -u postgres psql -d $DB_NAME << 'SQLEOF'
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO $DB_USER;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO $DB_USER;
GRANT USAGE, CREATE ON SCHEMA public TO $DB_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO $DB_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO $DB_USER;
SQLEOF
echo "✓ 数据库权限已确认"
# 使用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 ${SSH_HOST} 'pm2 logs chinese-family-tree'"
echo -e " - 重启应用: ssh ${SSH_HOST} 'pm2 restart chinese-family-tree'"
echo -e " - 停止应用: ssh ${SSH_HOST} 'pm2 stop chinese-family-tree'"
echo -e "${GREEN}========================================${NC}"
else
echo -e "${RED}✗ 部署失败${NC}"
exit 1
fi