#!/bin/bash # jsite前端自动化部署脚本 # 基于next.js + traefik开发 # # 后端调用示例: # 1. 基本部署: ./install_jsite.sh # 2. 指定项目: ./install_jsite.sh -p myproject -r http://git.example.com/myproject # 3. 跳过Docker: ./install_jsite.sh --skip-docker # 4. 跳过Traefik: ./install_jsite.sh --skip-traefik # 5. 强制更新: ./install_jsite.sh --force-update # 6. 完整参数: ./install_jsite.sh -p myproject -r http://git.example.com/myproject -n 18 --skip-docker --force-update # # 返回码: # 0 - 成功 # 1 - 参数错误 # 2 - 权限错误 # 3 - 其他错误 set -e # 遇到错误时退出 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 默认参数 PROJECT_NAME="jingrow" GIT_REPO="http://git.jingrow.com:3000/jsite/jingrow" NODE_VERSION="22" SKIP_DOCKER=false SKIP_TRAEFIK=false SKIP_DEPENDENCIES=false FORCE_UPDATE=false # .env文件参数 SITE_URL="http://192.168.2.200:3001" REVALIDATE_TOKEN="535bc122f3e364c" SITE_NAME="jingrow" SERVER_URL="https://admin.jingrow.com" API_KEY="535bc122f3e364c" API_SECRET="8629a3b12fc1cc2" # 显示帮助信息 show_help() { echo "用法: $0 [选项]" echo "" echo "选项:" echo " -p, --project-name NAME 项目名称 (默认: jingrow)" echo " -r, --repo URL Git仓库地址" echo " -n, --node-version VERSION Node.js版本 (默认: 22)" echo " --skip-docker 跳过Docker安装" echo " --skip-traefik 跳过Traefik安装和启动" echo " --skip-dependencies 跳过项目依赖安装" echo " --force-update 强制更新项目(如果已存在)" echo "" echo ".env文件配置:" echo " --site-url URL 网站URL (默认: http://192.168.2.200:3001)" echo " --revalidate-token TOKEN 重新验证令牌 (默认: 535bc122f3e364c)" echo " --site-name NAME 站点名称 (默认: jingrow)" echo " --server-url URL 服务器URL (默认: https://admin.jingrow.com)" echo " --api-key KEY API密钥 (默认: 535bc122f3e364c)" echo " --api-secret SECRET API密钥 (默认: 8629a3b12fc1cc2)" echo "" echo " -h, --help 显示此帮助信息" echo "" echo "示例:" echo " $0 -p myproject -r http://git.example.com/myproject" echo " $0 --skip-docker --skip-traefik" echo " $0 --force-update" echo " $0 --site-url http://example.com --site-name myproject" } # 解析命令行参数 parse_arguments() { while [[ $# -gt 0 ]]; do case $1 in -p|--project-name) PROJECT_NAME="$2" shift 2 ;; -r|--repo) GIT_REPO="$2" shift 2 ;; -n|--node-version) NODE_VERSION="$2" shift 2 ;; --skip-docker) SKIP_DOCKER=true shift ;; --skip-traefik) SKIP_TRAEFIK=true shift ;; --skip-dependencies) SKIP_DEPENDENCIES=true shift ;; --force-update) FORCE_UPDATE=true shift ;; --site-url) SITE_URL="$2" shift 2 ;; --revalidate-token) REVALIDATE_TOKEN="$2" shift 2 ;; --site-name) SITE_NAME="$2" shift 2 ;; --server-url) SERVER_URL="$2" shift 2 ;; --api-key) API_KEY="$2" shift 2 ;; --api-secret) API_SECRET="$2" shift 2 ;; -h|--help) show_help exit 0 ;; *) echo -e "${RED}[ERROR]${NC} 未知参数: $1" show_help exit 1 ;; esac done } # 日志函数 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 -eq 0 ]]; then log_info "以root用户身份运行脚本" else log_error "请以root用户身份运行此脚本" exit 1 fi } # 1. 创建jingrow用户 create_jingrow_user() { log_info "开始创建jingrow用户..." if id "jingrow" &>/dev/null; then log_warning "用户jingrow已存在" else useradd -m -s /bin/bash jingrow log_success "用户jingrow创建成功" fi # 确保home目录存在 if [ ! -d "/home/jingrow" ]; then mkdir -p /home/jingrow chown jingrow:jingrow /home/jingrow log_success "创建/home/jingrow目录" fi } # 2. 安装nvm和node.js install_nodejs() { log_info "开始安装nvm和node.js..." # 切换到jingrow用户目录 cd /home/jingrow # 下载并安装nvm if [ ! -d "/home/jingrow/.nvm" ]; then log_info "下载并安装nvm..." su - jingrow -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash" log_success "nvm安装完成" else log_warning "nvm已存在" fi # 加载nvm并安装node.js log_info "安装Node.js v$NODE_VERSION..." su - jingrow -c " export NVM_DIR=\"\$HOME/.nvm\" [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" nvm install $NODE_VERSION nvm use $NODE_VERSION nvm alias default $NODE_VERSION " # 验证安装 NODE_VERSION_OUTPUT=$(su - jingrow -c 'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && node -v') NPM_VERSION=$(su - jingrow -c 'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && npm -v') log_success "Node.js版本: $NODE_VERSION_OUTPUT" log_success "npm版本: $NPM_VERSION" } # 3. 克隆jsite项目 clone_jsite_project() { log_info "开始克隆jsite项目: $PROJECT_NAME..." cd /home/jingrow # 创建jsite目录(如果不存在) if [ ! -d "/home/jingrow/jsite" ]; then mkdir -p /home/jingrow/jsite chown jingrow:jingrow /home/jingrow/jsite log_success "创建jsite目录" fi # 检查项目子目录是否已存在 if [ -d "/home/jingrow/jsite/$PROJECT_NAME" ]; then if [ "$FORCE_UPDATE" = true ]; then log_warning "项目目录已存在,强制更新..." rm -rf "/home/jingrow/jsite/$PROJECT_NAME" cd /home/jingrow/jsite su - jingrow -c "cd /home/jingrow/jsite && git clone $GIT_REPO $PROJECT_NAME" log_success "jsite/$PROJECT_NAME项目更新完成" else log_warning "jsite/$PROJECT_NAME目录已存在,跳过克隆" fi else cd /home/jingrow/jsite su - jingrow -c "cd /home/jingrow/jsite && git clone $GIT_REPO $PROJECT_NAME" log_success "jsite/$PROJECT_NAME项目克隆完成" fi } # 4. 创建.env文件 create_env_file() { log_info "创建.env文件..." cd /home/jingrow/jsite/$PROJECT_NAME # 检查.env文件是否已存在 if [ -f "/home/jingrow/jsite/$PROJECT_NAME/.env" ]; then if [ "$FORCE_UPDATE" = true ]; then log_warning ".env文件已存在,强制更新..." else log_warning ".env文件已存在,跳过创建" return fi fi # 创建.env文件 cat > "/home/jingrow/jsite/$PROJECT_NAME/.env" << EOF PUBLIC_SITE_URL=$SITE_URL REVALIDATE_TOKEN=$REVALIDATE_TOKEN JINGROW_SITE_NAME=$SITE_NAME JINGROW_SERVER_URL=$SERVER_URL JINGROW_API_KEY=$API_KEY JINGROW_API_SECRET=$API_SECRET EOF # 设置文件权限 chown jingrow:jingrow "/home/jingrow/jsite/$PROJECT_NAME/.env" chmod 600 "/home/jingrow/jsite/$PROJECT_NAME/.env" log_success ".env文件创建完成" } # 5. 安装traefik install_traefik() { log_info "开始安装traefik..." cd /home/jingrow # 创建traefik目录结构 if [ ! -d "/home/jingrow/traefik" ]; then mkdir -p /home/jingrow/traefik/conf.d log_success "创建traefik目录结构" fi # 创建acme.json文件 if [ ! -f "/home/jingrow/traefik/acme.json" ]; then touch /home/jingrow/traefik/acme.json chmod 600 /home/jingrow/traefik/acme.json log_success "创建acme.json文件" fi # 创建traefik.yml配置文件 cat > /home/jingrow/traefik/traefik.yml << 'EOF' entryPoints: web: address: ":80" websecure: address: ":443" api: dashboard: true insecure: true # 生产环境建议关闭 providers: docker: exposedByDefault: false file: directory: /etc/traefik/conf.d watch: true certificatesResolvers: myresolver: acme: email: support@jingrow.com storage: acme.json httpChallenge: entryPoint: web EOF log_success "创建traefik.yml配置文件" # 创建docker-compose.yml文件 cat > /home/jingrow/traefik/docker-compose.yml << 'EOF' services: traefik: # The official v3 Traefik docker image image: traefik:v3.4 container_name: traefik restart: always # Enables the web UI and tells Traefik to listen to docker command: --api.insecure=true --providers.docker ports: # The HTTP port - "80:80" - "443:443" # The Web UI (enabled by --api.insecure=true) - "8080:8080" volumes: # So that Traefik can listen to the Docker events - /var/run/docker.sock:/var/run/docker.sock - ./traefik.yml:/etc/traefik/traefik.yml:ro - ./conf.d:/etc/traefik/conf.d:ro - ./acme.json:/etc/traefik/acme.json EOF log_success "创建docker-compose.yml文件" # 设置目录权限 chown -R jingrow:jingrow /home/jingrow/traefik log_success "设置traefik目录权限" } # 6. 安装Docker(如果未安装) install_docker() { log_info "检查Docker安装状态..." if command -v docker &> /dev/null; then log_warning "Docker已安装" else log_info "开始安装Docker..." # 更新包索引 apt-get update # 安装必要的包 apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release # 添加Docker官方GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 设置稳定版仓库 echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null # 更新包索引 apt-get update # 安装Docker Engine apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # 启动Docker服务 systemctl start docker systemctl enable docker log_success "Docker安装完成" fi # 将jingrow用户添加到docker组 usermod -aG docker jingrow log_success "将jingrow用户添加到docker组" } # 7. 启动traefik start_traefik() { log_info "启动traefik服务..." cd /home/jingrow/traefik # 使用jingrow用户启动traefik su - jingrow -c "cd /home/jingrow/traefik && docker compose up -d" log_success "traefik服务启动完成" } # 8. 安装项目依赖 install_project_dependencies() { log_info "安装jsite/$PROJECT_NAME项目依赖..." cd /home/jingrow/jsite/$PROJECT_NAME su - jingrow -c " export NVM_DIR=\"\$HOME/.nvm\" [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" cd /home/jingrow/jsite/$PROJECT_NAME npm install " log_success "项目依赖安装完成" } # 9. 显示部署信息 show_deployment_info() { log_success "=== 部署完成 ===" echo "" log_info "部署信息:" echo " - 用户: jingrow" echo " - jsite目录: /home/jingrow/jsite" echo " - 项目目录: /home/jingrow/jsite/$PROJECT_NAME" echo " - Traefik目录: /home/jingrow/traefik" echo " - Traefik管理界面: http://localhost:8080" echo "" log_info ".env文件配置:" echo " - PUBLIC_SITE_URL: $SITE_URL" echo " - JINGROW_SITE_NAME: $SITE_NAME" echo " - JINGROW_SERVER_URL: $SERVER_URL" echo " - REVALIDATE_TOKEN: $REVALIDATE_TOKEN" echo " - JINGROW_API_KEY: $API_KEY" echo " - JINGROW_API_SECRET: $API_SECRET" echo "" log_info "下一步操作:" echo " 1. 进入项目目录: cd /home/jingrow/jsite/$PROJECT_NAME" echo " 2. 启动开发服务器: npm run dev" echo " 3. 访问Traefik管理界面: http://localhost:8080" echo "" log_warning "注意:请确保防火墙允许80、443、8080端口访问" } # 主函数 main() { log_info "开始jsite前端自动化部署..." echo "" log_info "部署参数:" echo " - 项目名称: $PROJECT_NAME" echo " - Git仓库: $GIT_REPO" echo " - Node.js版本: $NODE_VERSION" echo " - 跳过Docker: $SKIP_DOCKER" echo " - 跳过Traefik: $SKIP_TRAEFIK" echo " - 跳过依赖安装: $SKIP_DEPENDENCIES" echo " - 强制更新: $FORCE_UPDATE" echo "" log_info ".env文件参数:" echo " - 网站URL: $SITE_URL" echo " - 站点名称: $SITE_NAME" echo " - 服务器URL: $SERVER_URL" echo " - 重新验证令牌: $REVALIDATE_TOKEN" echo " - API密钥: $API_KEY" echo " - API密钥: $API_SECRET" echo "" check_root create_jingrow_user if [ "$SKIP_DOCKER" = false ]; then install_docker else log_warning "跳过Docker安装" fi install_nodejs clone_jsite_project create_env_file if [ "$SKIP_TRAEFIK" = false ]; then install_traefik start_traefik else log_warning "跳过Traefik安装和启动" fi if [ "$SKIP_DEPENDENCIES" = false ]; then install_project_dependencies else log_warning "跳过项目依赖安装" fi show_deployment_info log_success "部署脚本执行完成!" } # 执行主函数 parse_arguments "$@" main "$@"