From 5308a10b5224c3681f4607f28a0933d5f3ecf381 Mon Sep 17 00:00:00 2001 From: shiyue Date: Fri, 12 Jun 2026 14:23:14 +0800 Subject: [PATCH] docs: add PM2 one-click start --- README.md | 50 +++++++++++++++++++++++++- start.sh | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 1 deletion(-) create mode 100755 start.sh diff --git a/README.md b/README.md index e641ee4..274b135 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,16 @@ https://github.com/ZgDaniel/cc-web 给我装! ```bash git clone https://github.com/ZgDaniel/cc-web.git cd cc-web -npm install cp .env.example .env # 可选,不设密码则首次启动自动生成 +./start.sh +``` + +`start.sh` 会检查 Node.js/npm 环境,自动安装 PM2(如未安装),安装项目依赖,并以 `ccweb` 为默认应用名启动或重启服务。 + +如只想前台临时运行,也可以手动执行: + +```bash +npm install npm start ``` @@ -137,6 +145,7 @@ cc-web/ │ ├── mock-claude.js # 回归用 mock Claude CLI │ └── mock-codex.js # 回归用 mock Codex CLI ├── .env.example # 环境变量模板 +├── start.sh # Linux / macOS PM2 一键启动脚本 ├── start.bat # Windows 一键启动脚本 ├── .gitignore ├── package.json @@ -186,6 +195,45 @@ tail -f logs/process.log | jq . ## 生产部署 +### PM2 一键启动 + +推荐在 Linux 服务器使用非 root 用户部署: + +```bash +git clone https://github.com/ZgDaniel/cc-web.git +cd cc-web +cp .env.example .env # 可选,不设密码则首次启动自动生成 +./start.sh +``` + +脚本默认执行以下动作: + +- 检查 Node.js >= 18 与 npm +- 检查 PM2,未安装时自动执行 `npm install -g pm2` +- 使用 `npm ci` 安装项目依赖(无 `package-lock.json` 时退回 `npm install`) +- 使用 PM2 启动或重启 `server.js`,默认应用名为 `ccweb` +- 执行 `pm2 save` 保存当前进程快照 + +常用命令: + +```bash +pm2 status ccweb +pm2 logs ccweb +pm2 restart ccweb --update-env +``` + +如果需要服务器重启后自动恢复 PM2 进程,请执行: + +```bash +pm2 startup +``` + +然后按命令输出的提示执行生成的 `sudo ...` 命令,最后再次执行: + +```bash +pm2 save +``` + ### systemd 服务 创建 `/etc/systemd/system/cc-web.service`: diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..64c3213 --- /dev/null +++ b/start.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +APP_NAME="${CC_WEB_PM2_NAME:-ccweb}" +ENTRY_FILE="${CC_WEB_ENTRY:-server.js}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +APP_DIR="${SCRIPT_DIR}" +ENTRY_PATH="${APP_DIR}/${ENTRY_FILE}" + +log() { + printf '[cc-web pm2] %s\n' "$*" +} + +fail() { + printf '[cc-web pm2] ERROR: %s\n' "$*" >&2 + exit 1 +} + +ensure_command() { + local cmd="$1" + local hint="$2" + if ! command -v "${cmd}" >/dev/null 2>&1; then + fail "${cmd} 未安装。${hint}" + fi +} + +install_pm2() { + if command -v pm2 >/dev/null 2>&1; then + log "PM2 已安装: $(command -v pm2)" + return + fi + + log "未检测到 PM2,开始安装..." + if npm install -g pm2; then + log "PM2 安装完成" + return + fi + + if command -v sudo >/dev/null 2>&1; then + log "普通 npm 全局安装失败,尝试使用 sudo 安装 PM2..." + sudo npm install -g pm2 + log "PM2 安装完成" + return + fi + + fail "PM2 自动安装失败,且当前环境没有 sudo。请先手动安装: npm install -g pm2" +} + +install_dependencies() { + cd "${APP_DIR}" + + if [[ -f package-lock.json ]]; then + log "安装项目依赖: npm ci" + npm ci + else + log "安装项目依赖: npm install" + npm install + fi +} + +start_or_restart_app() { + cd "${APP_DIR}" + + if pm2 describe "${APP_NAME}" >/dev/null 2>&1; then + log "PM2 应用已存在,执行重启: ${APP_NAME}" + pm2 restart "${APP_NAME}" --update-env + else + log "启动 PM2 应用: ${APP_NAME}" + pm2 start "${ENTRY_PATH}" --name "${APP_NAME}" --cwd "${APP_DIR}" + fi + + log "保存 PM2 进程快照" + pm2 save + + log "当前 PM2 状态" + pm2 status "${APP_NAME}" +} + +main() { + if [[ "$(id -u)" -eq 0 ]]; then + fail "请使用非 root 用户执行。该服务会启动 Claude/Codex 子进程,root 运行风险过高。" + fi + + [[ -f "${ENTRY_PATH}" ]] || fail "找不到入口文件: ${ENTRY_PATH}" + + ensure_command node "请先安装 Node.js 18 或更高版本。" + ensure_command npm "请先安装 npm。" + + local node_major + node_major="$(node -p "Number(process.versions.node.split('.')[0])")" + if [[ "${node_major}" -lt 18 ]]; then + fail "Node.js 版本过低,当前为 $(node -v),要求 >= 18。" + fi + + install_pm2 + install_dependencies + start_or_restart_app + + log "完成。若需要开机自启,请执行 pm2 startup,并按输出提示执行生成的命令。" +} + +main "$@"