使用 Webhooks:这是 Gogs 官方推荐的、更现代、更灵活的方式。它通过 HTTP 请求通知你的服务器进行部署。这种方法的核心思想是:当 Gogs 收到 git push 时,它会向你配置的一个 URL 发送一个带有提交信息的 POST 请求。你的 Web 服务器上需要有一个小的应用一直监听这个 URL,收到请求后执行部署脚本。
首先,确保你已经有一个可以正常工作的部署脚本,就像上一个回答中提到的那样。我们假设它位于 /home/myuser/deploy.sh。
#!/bin/bash
# /home/myuser/deploy.sh
set -e
PROJECT_DIR="/usr/local/nginx/html/huahuibao"
GIT_BRANCH="dev"
echo "======== [Webhook GO] 部署开始 `date` ========"
cd $PROJECT_DIR
unset GIT_DIR
/usr/local/git/bin/git reset --hard
/usr/local/git/bin/git pull origin $GIT_BRANCH
cd
# ... 其他构建或重启命令 ...
# 例如:
# echo "正在重启服务..."
# sudo systemctl restart my-app
echo "======== [Webhook dev分支] 部署成功 `date` ========"
此代码放在测试服 /root/Code/go/gogs-webhook-listener 目录下
创建一个名为 gogs-webhook-listener 的文件夹,并在其中创建一个 main.go 文件。
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
)
// --- 配置项 ---
// 这些值可以硬编码,也可以通过环境变量或配置文件传入
const (
// Webhook 监听地址和端口
listenAddr = "0.0.0.0:8000"
// Gogs Webhook 中设置的密钥,!!务必修改为你的密钥!!
gogsSecret = "gogs_secret_key-xhb*2025"
// 要执行的部署脚本路径
deployScriptPath = "/root/sh/gogs_deploy.sh"
// 只对这个分支的 push 事件做出反应
targetBranch = "refs/heads/dev"
// Webhook 访问路径
webhookPath = "/webhook"
)
// GogsPushPayload 定义了我们关心的 Gogs push 事件的 JSON 结构体字段
type GogsPushPayload struct {
Ref string `json:"ref"` // The full git ref that was pushed. Example: "refs/heads/master".
}
func main() {
http.HandleFunc(webhookPath, handleWebhook)
log.Printf("Gogs Webhook 监听服务已启动,地址: http://%s%s\n", listenAddr, webhookPath)
if err := http.ListenAndServe(listenAddr, nil); err != nil {
log.Fatalf("启动 HTTP 服务失败: %v", err)
}
}
// handleWebhook 是处理所有进入 webhookPath 的请求的函数
func handleWebhook(w http.ResponseWriter, r *http.Request) {
// 1. 检查请求方法是否为 POST
if r.Method != http.MethodPost {
log.Printf("无效的请求方法: %s", r.Method)
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
return
}
// 2. 读取请求体
body, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("读取请求体失败: %v", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
defer r.Body.Close()
// 3. 验证签名 (关键安全步骤)
gogsSignature := r.Header.Get("X-Gogs-Signature")
if !isValidSignature(body, gogsSecret, gogsSignature) {
log.Println("签名验证失败!请求来源可疑。")
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
// 4. 检查是否为 'push' 事件
if r.Header.Get("X-Gogs-Event") != "push" {
log.Println("接收到非 push 事件,已忽略。")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "Not a push event, ignored.")
return
}
// 5. 解析 JSON 并检查分支
var payload GogsPushPayload
if err := json.Unmarshal(body, &payload); err != nil {
log.Printf("解析 JSON payload 失败: %v", err)
http.Error(w, "Invalid payload", http.StatusBadRequest)
return
}
if payload.Ref != targetBranch {
log.Printf("接收到对分支 '%s' 的 push,已忽略。目标分支为 '%s'。", payload.Ref, targetBranch)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Push to branch %s ignored.", payload.Ref)
return
}
// 6. 执行部署脚本
log.Printf("验证通过,开始执行部署脚本: %s", deployScriptPath)
cmd := exec.Command("sh", deployScriptPath)
// 将脚本的标准输出和标准错误输出重定向到 Go 程序的日志
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Printf("执行部署脚本失败: %v", err)
http.Error(w, "Deployment script execution failed", http.StatusInternalServerError)
return
}
log.Println("部署脚本执行成功。")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "Deployment triggered successfully.")
}
// isValidSignature 验证 Gogs 的 HMAC-SHA256 签名
func isValidSignature(body []byte, secret, signature string) bool {
if signature == "" {
return false
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expectedMAC := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expectedMAC))
}
代码放在测试服 /root 目录下
初始化 Go Module (如果你还没有的话)
在 gogs-webhook-listener 目录下执行:
go mod init gogs-webhook-listener
构建二进制文件 这个命令会生成一个名为 gogs-webhook-listener 的可执行文件。
go build .
运行服务 可以直接在前台运行进行测试:
./gogs-webhook-listener
你应该会看到日志输出: Gogs Webhook 监听服务已启动,地址: http://0.0.0.0:8000/webhook
为了让这个服务在服务器上长期稳定地运行,并能开机自启,最好将它配置成一个 systemd 服务。
创建 service 文件:
vim /etc/systemd/system/gogs-webhook.service
写入以下内容。注意修改 User 和 ExecStart 的路径。
[Unit]
Description=Gogs Webhook Listener for Auto Deployment
After=network.target
[Service]
Type=simple
# 建议创建一个专门的用户来运行此服务
User=root
# ExecStart 指向你编译好的二进制文件的绝对路径
ExecStart=/root/Code/go/gogs-webhook-listener/gogs-webhook-listener
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
重载 systemd 并启动服务:
systemctl daemon-reload
systemctl start gogs-webhook.service
检查服务状态:
systemctl status gogs-webhook.service
如果一切正常,它应该显示 active (running)。
设置开机自启:
systemctl enable gogs-webhook.service