webman需手动实现gitlab webhook解析:先用file_get_contents('php://input')获取原始json,再以x-hub-signature-256头做hmac-sha256验签,确认event_name为'push'且仓库匹配后,异步触发部署脚本。

Webman 本身不内置 GitLab Webhook 解析逻辑,必须手动实现签名验证、事件路由和部署动作——直接 $_POST 或 file_get_contents('php://input') 读取原始 payload 就会失败,因为 GitLab 默认用 application/json 发送,且要求 HMAC-SHA256 签名校验。
GitLab Webhook 的 signature 验证必须手写
GitLab 发送的请求带 X-Gitlab-Token(自定义 token)或 X-Gitlab-Event + X-Hub-Signature-256(HMAC),后者才是标准做法。Webman 没有现成中间件做这件事,得自己在路由里处理:
-
X-Hub-Signature-256值形如sha256=abc123...,需截取后半段,用hash_hmac('sha256', $raw_body, $secret_token, true)计算比对 - 必须用
file_get_contents('php://input')获取原始 JSON,不能依赖$_POST(它为空) - 若用
json_decode(file_get_contents('php://input'), true)后再验证,顺序错——得先验签再解码,否则可能被篡改 payload 绕过
只响应 PushEvents,忽略 MergeRequestEvents 等其他类型
GitLab Webhook 可能发多种事件,但自动部署通常只关心 push。别假设所有请求都该触发部署:
- 检查
$payload['event_name'] === 'push',不是$_SERVER['HTTP_X_GITLAB_EVENT'](旧版字段,新版已弃用) - 确认
$payload['repository']['name']和$payload['repository']['path_with_namespace']匹配目标仓库,避免误触发其他项目 - 过滤掉
$payload['before'] === $payload['after']的空提交,或count($payload['commits']) === 0的 tag 推送(除非你真要部署 tag)
执行部署命令必须脱离 Webman 主进程
在 Webman 路由里直接 shell_exec('git pull && composer install') 是危险的:超时、阻塞、权限错、输出乱码都会导致 webhook 失败或卡死。正确做法是异步转交:
- 用
pcntl_fork()派生子进程,父进程立即返回 HTTP 200;子进程调用exec()并重定向 stdout/stderr 到日志文件 - 更稳的方式是写入 Redis 队列(如
redis-cli lpush deploy:queue '{"repo":"xxx","branch":"main"}'),另起一个php worker.php守护进程监听并执行 - 确保执行用户(通常是
www)对项目目录有读写权限,且 SSH key 已配置好(git pull用 HTTPS 还是 SSH?HTTPS 需带 token,SSH 需免密登录)
宝塔面板下 Webman 进程守护与部署脚本的协作
宝塔的“进程守护管理器”只管 server.bin 是否存活,不管部署逻辑是否成功。它不会帮你拉代码、装依赖、清缓存:
- 部署脚本(如
deploy.sh)应放在项目根目录,内容包括cd /www/wwwroot/your-site && git pull origin main && composer install --no-dev && php webman clean - Webman 接收到 webhook 后,不应直接执行
sh deploy.sh,而应通过proc_open()或队列触发,并记录proc_get_status()返回码判断成败 - 宝塔里添加的“计划任务”不能替代 webhook 触发——它定时拉代码,无法响应 GitLab 实时推送,容易漏部署
GitLab Webhook 的 secret token 和 Webman 的部署路径、用户权限、进程模型三者必须对齐,缺一不可;任何一层没配对,就会出现“请求 200 但没反应”或“报错 500 却看不到日志”的静默失败。











