使用宝塔面板的 Webhook 功能实现代码自动同步,核心是在代码仓库(如 GitHub、Gitee)和服务器之间建立一个自动触发的更新机制。
以下是基于宝塔面板的完整配置流程。
整体流程概览
#mermaid-svg-x6Xo2n2jRBFGhQrG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-x6Xo2n2jRBFGhQrG .error-icon{fill:#552222;}#mermaid-svg-x6Xo2n2jRBFGhQrG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-x6Xo2n2jRBFGhQrG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .marker.cross{stroke:#333333;}#mermaid-svg-x6Xo2n2jRBFGhQrG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-x6Xo2n2jRBFGhQrG p{margin:0;}#mermaid-svg-x6Xo2n2jRBFGhQrG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .cluster-label text{fill:#333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .cluster-label span{color:#333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .cluster-label span p{background-color:transparent;}#mermaid-svg-x6Xo2n2jRBFGhQrG .label text,#mermaid-svg-x6Xo2n2jRBFGhQrG span{fill:#333;color:#333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .node rect,#mermaid-svg-x6Xo2n2jRBFGhQrG .node circle,#mermaid-svg-x6Xo2n2jRBFGhQrG .node ellipse,#mermaid-svg-x6Xo2n2jRBFGhQrG .node polygon,#mermaid-svg-x6Xo2n2jRBFGhQrG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-x6Xo2n2jRBFGhQrG .rough-node .label text,#mermaid-svg-x6Xo2n2jRBFGhQrG .node .label text,#mermaid-svg-x6Xo2n2jRBFGhQrG .image-shape .label,#mermaid-svg-x6Xo2n2jRBFGhQrG .icon-shape .label{text-anchor:middle;}#mermaid-svg-x6Xo2n2jRBFGhQrG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-x6Xo2n2jRBFGhQrG .rough-node .label,#mermaid-svg-x6Xo2n2jRBFGhQrG .node .label,#mermaid-svg-x6Xo2n2jRBFGhQrG .image-shape .label,#mermaid-svg-x6Xo2n2jRBFGhQrG .icon-shape .label{text-align:center;}#mermaid-svg-x6Xo2n2jRBFGhQrG .node.clickable{cursor:pointer;}#mermaid-svg-x6Xo2n2jRBFGhQrG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .arrowheadPath{fill:#333333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-x6Xo2n2jRBFGhQrG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x6Xo2n2jRBFGhQrG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-x6Xo2n2jRBFGhQrG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x6Xo2n2jRBFGhQrG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-x6Xo2n2jRBFGhQrG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-x6Xo2n2jRBFGhQrG .cluster text{fill:#333;}#mermaid-svg-x6Xo2n2jRBFGhQrG .cluster span{color:#333;}#mermaid-svg-x6Xo2n2jRBFGhQrG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-x6Xo2n2jRBFGhQrG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-x6Xo2n2jRBFGhQrG rect.text{fill:none;stroke-width:0;}#mermaid-svg-x6Xo2n2jRBFGhQrG .icon-shape,#mermaid-svg-x6Xo2n2jRBFGhQrG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x6Xo2n2jRBFGhQrG .icon-shape p,#mermaid-svg-x6Xo2n2jRBFGhQrG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-x6Xo2n2jRBFGhQrG .icon-shape .label rect,#mermaid-svg-x6Xo2n2jRBFGhQrG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x6Xo2n2jRBFGhQrG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-x6Xo2n2jRBFGhQrG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-x6Xo2n2jRBFGhQrG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} "触发Webhook"
"执行"
"运行"
"执行git pull"
开发者推送代码到仓库
代码仓库(GitHub/Gitee等)
向宝塔Webhook插件配置的URL发送POST请求
宝塔Webhook插件
预先配置好的Shell脚本
服务器上的网站目录
网站代码更新完成
详细配置步骤
1. 服务器端环境准备
- 安装Git :确保服务器已安装Git。可通过SSH连接到服务器,运行
git --version检查。若未安装,可执行yum install git -y(CentOS) 或apt-get install git -y(Ubuntu)。 - 配置SSH密钥(推荐) :为了避免每次拉取代码时输入密码,推荐使用SSH方式连接代码仓库。
-
以
www用户身份生成SSH密钥(Webhook脚本默认以www用户执行,这能避免很多权限问题):bashsudo -u www ssh-keygen -t rsa -C "your_email@example.com" -
查看并复制公钥:
cat /home/www/.ssh/id_rsa.pub。 -
将公钥添加到你的代码仓库(GitHub/Gitee/GitLab)的 Deploy Keys 或 SSH Keys 中。
-
2. 在宝塔面板安装并配置 Webhook 插件
-
安装插件 :登录宝塔面板,进入"软件商店",搜索"WebHook"并安装。
-
添加Hook :安装完成后,在左侧菜单点击"WebHook"进入管理页面,点击"添加Hook"。
-
填写信息 :
-
Hook名称 :自定义一个名称,如
auto_deploy。 -
脚本内容 :填入用于拉取代码的Shell脚本。这是一个基础但完整的脚本模板,你需要根据实际情况修改变量值:
bash#!/bin/bash echo "" # 输出当前时间 date --date='0 days ago' "+%Y-%m-%d %H:%M:%S" echo "Start" # --- 请修改以下三个变量为你的项目信息 --- branch="main" # 你的代码分支,如 main 或 master gitPath="/www/wwwroot/your_site.com" # 你网站代码在服务器上的绝对路径 gitHttp="git@github.com:your_username/your_repo.git" # 你的仓库SSH地址 # -------------------------------------- echo "Web站点路径:$gitPath" # 判断项目路径是否存在 if [ -d "$gitPath" ]; then cd $gitPath # 如果目录下没有 .git 文件夹,则执行克隆 if [ ! -d ".git" ]; then echo "在该目录下克隆 git" sudo git clone $gitHttp gittemp sudo mv gittemp/.git . sudo rm -rf gittemp fi echo "拉取最新的项目文件" # 拉取最新代码,并强制与远程分支保持一致 sudo git reset --hard origin/$branch sudo git pull $gitHttp 2>&1 echo "设置目录权限" # 将目录所有者设为 www,确保网站运行用户有权限 sudo chown -R www:www $gitPath echo "代码拉取结束" # --- 可以在此处添加项目构建命令,如 npm install, npm run build 等 --- # 例如:npm install && npm run build # ------------------------------------------------------------------ echo "End" exit else echo "该项目路径不存在" exit fi
-
-
保存:点击"添加"或"保存"按钮。
3. 在代码仓库配置 Webhook
- 获取宝塔Webhook的URL和密钥 :在宝塔的"WebHook"管理页面,找到刚创建的Hook,点击"查看密钥 "。你会得到一个URL(如
http://你的服务器IP:端口/hook?access_key=xxx)和密钥(access_key)。 - 配置仓库Webhook:登录你的代码托管平台(如GitHub、Gitee),进入你的项目仓库 -> "设置"(Settings) -> "Webhooks" -> "添加 Webhook"(Add webhook)。
- 填写信息 :
- Payload URL:粘贴从宝塔复制的完整URL。
- Content type :选择
application/json。 - Secret :此处的Secret与宝塔的
access_key不是同一个概念,一般可以留空。宝塔插件通过URL中的access_key参数进行身份验证。 - 触发事件 :选择"Just the push event",这样只在代码被推送时触发。
- 保存:点击"添加 Webhook"。
常见问题与解决方案
- 脚本执行但代码未更新 :通常是权限问题 。Webhook脚本默认以
www用户执行,如果代码目录不是www用户所有,或www用户没有SSH密钥的读取权限,就会失败。解决方法是在脚本中显式使用sudo -u www并确保目录权限正确。 Permission denied (publickey):这表明SSH密钥认证失败。请确保:- SSH密钥是为
www用户生成的。 - 公钥已正确添加到代码仓库。
- 脚本中使用了正确的仓库SSH地址(如
git@github.com:...)。
- SSH密钥是为
fatal: dubious ownership:Git的安全机制。在脚本的git pull命令前加入git config --global --add safe.directory $gitPath即可解决。- 如何测试 :配置完成后,你可以修改代码并推送到仓库,然后观察宝塔Webhook的"日志 "以及代码托管平台Webhook的"Recent Deliveries"来排查问题。